diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomBase.h b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomBase.h index fe731f4ad6..b329a35977 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomBase.h +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomBase.h @@ -155,8 +155,10 @@ namespace AZ enum AuxGeomShapeType { ShapeType_Sphere, + ShapeType_Hemisphere, ShapeType_Cone, ShapeType_Cylinder, + ShapeType_CylinderNoEnds, // Cylinder without disks on either end ShapeType_Disk, ShapeType_Quad, diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp index 29db7d6673..7c713af96a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp @@ -314,15 +314,35 @@ namespace AZ AddShape(style, shape); } - void AuxGeomDrawQueue::DrawSphere( - const AZ::Vector3& center, + Matrix3x3 CreateMatrix3x3FromDirection(const AZ::Vector3& direction) + { + Vector3 unitDirection(direction.GetNormalized()); + Vector3 unitOrthogonal(direction.GetOrthogonalVector().GetNormalized()); + Vector3 unitCross(unitOrthogonal.Cross(unitDirection)); + return Matrix3x3::CreateFromColumns(unitOrthogonal, unitDirection, unitCross); + } + + void AuxGeomDrawQueue::DrawSphere(const AZ::Vector3& center, float radius, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) + { + DrawSphereCommon(center, AZ::Vector3::CreateAxisY(), radius, color, style, depthTest, depthWrite, faceCull, viewProjOverrideIndex, false); + } + + void AuxGeomDrawQueue::DrawHemisphere(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) + { + DrawSphereCommon(center, direction, radius, color, style, depthTest, depthWrite, faceCull, viewProjOverrideIndex, true); + } + + void AuxGeomDrawQueue::DrawSphereCommon( + const AZ::Vector3& center, + const AZ::Vector3& direction, float radius, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, - int32_t viewProjOverrideIndex) + int32_t viewProjOverrideIndex, + bool isHemisphere) { if (radius <= 0.0f) { @@ -330,12 +350,12 @@ namespace AZ } ShapeBufferEntry shape; - shape.m_shapeType = ShapeType_Sphere; + shape.m_shapeType = isHemisphere ? ShapeType_Hemisphere : ShapeType_Sphere; shape.m_depthRead = ConvertRPIDepthTestFlag(depthTest); shape.m_depthWrite = ConvertRPIDepthWriteFlag(depthWrite); shape.m_faceCullMode = ConvertRPIFaceCullFlag(faceCull); shape.m_color = color; - shape.m_rotationMatrix = Matrix3x3::CreateIdentity(); + shape.m_rotationMatrix = CreateMatrix3x3FromDirection(direction); shape.m_position = center; shape.m_scale = AZ::Vector3(radius, radius, radius); shape.m_pointSize = m_pointSize; @@ -362,13 +382,9 @@ namespace AZ shape.m_faceCullMode = ConvertRPIFaceCullFlag(faceCull); shape.m_color = color; - Vector3 unitDirection(direction.GetNormalized()); - Vector3 unitOrthogonal(direction.GetOrthogonalVector().GetNormalized()); - Vector3 unitCross(unitOrthogonal.Cross(unitDirection)); - // The disk mesh is created with the top of the disk pointing along the positive Y axis. This creates a // rotation so that the top of the disk will point along the given direction vector. - shape.m_rotationMatrix = Matrix3x3::CreateFromColumns(unitOrthogonal, unitDirection, unitCross); + shape.m_rotationMatrix = CreateMatrix3x3FromDirection(direction); shape.m_position = center; shape.m_scale = AZ::Vector3(radius, 1.0f, radius); shape.m_pointSize = m_pointSize; @@ -401,13 +417,7 @@ namespace AZ shape.m_faceCullMode = ConvertRPIFaceCullFlag(faceCull); shape.m_color = color; - Vector3 unitDirection(direction.GetNormalized()); - Vector3 unitOrthogonal(direction.GetOrthogonalVector().GetNormalized()); - Vector3 unitCross(unitOrthogonal.Cross(unitDirection)); - - // The cone mesh is created with the tip of the cone pointing along the positive Y axis. This creates a - // rotation so that the tip of the cone will point along the given direction vector. - shape.m_rotationMatrix = Matrix3x3::CreateFromColumns(unitOrthogonal, unitDirection, unitCross); + shape.m_rotationMatrix = CreateMatrix3x3FromDirection(direction); shape.m_position = center; shape.m_scale = AZ::Vector3(radius, height, radius); shape.m_pointSize = m_pointSize; @@ -416,17 +426,30 @@ namespace AZ AddShape(style, shape); } - void AuxGeomDrawQueue::DrawCylinder( - const AZ::Vector3& center, - const AZ::Vector3& direction, - float radius, - float height, - const AZ::Color& color, - DrawStyle style, - DepthTest depthTest, - DepthWrite depthWrite, - FaceCullMode faceCull, - int32_t viewProjOverrideIndex) + void AuxGeomDrawQueue::DrawCylinder(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, float height, const AZ::Color& color, + DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) + { + DrawCylinderCommon(center, direction, radius, height, color, style, depthTest, depthWrite, faceCull, viewProjOverrideIndex, true); + } + + void AuxGeomDrawQueue::DrawCylinderNoEnds(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, float height, const AZ::Color& color, + DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) + { + DrawCylinderCommon(center, direction, radius, height, color, style, depthTest, depthWrite, faceCull, viewProjOverrideIndex, false); + } + + void AuxGeomDrawQueue::DrawCylinderCommon( + const AZ::Vector3& center, + const AZ::Vector3& direction, + float radius, + float height, + const AZ::Color& color, + DrawStyle style, + DepthTest depthTest, + DepthWrite depthWrite, + FaceCullMode faceCull, + int32_t viewProjOverrideIndex, + bool drawEnds) { if (radius <= 0.0f || height <= 0.0f) { @@ -434,19 +457,15 @@ namespace AZ } ShapeBufferEntry shape; - shape.m_shapeType = ShapeType_Cylinder; - shape.m_depthRead = ConvertRPIDepthTestFlag(depthTest); + shape.m_shapeType = drawEnds ? ShapeType_Cylinder : ShapeType_CylinderNoEnds; + shape.m_depthRead = ConvertRPIDepthTestFlag(depthTest); shape.m_depthWrite = ConvertRPIDepthWriteFlag(depthWrite); shape.m_faceCullMode = ConvertRPIFaceCullFlag(faceCull); shape.m_color = color; - Vector3 unitDirection(direction.GetNormalized()); - Vector3 unitOrthogonal(direction.GetOrthogonalVector().GetNormalized()); - Vector3 unitCross(unitOrthogonal.Cross(unitDirection)); - // The cylinder mesh is created with the top end cap of the cylinder facing along the positive Y axis. This creates a // rotation so that the top face of the cylinder will face along the given direction vector. - shape.m_rotationMatrix = Matrix3x3::CreateFromColumns(unitOrthogonal, unitDirection, unitCross); + shape.m_rotationMatrix = CreateMatrix3x3FromDirection(direction); shape.m_position = center; shape.m_scale = AZ::Vector3(radius, height, radius); shape.m_pointSize = m_pointSize; diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.h b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.h index 535a992fe0..2356abdf52 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.h +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.h @@ -60,9 +60,11 @@ namespace AZ // Fixed shape draws void DrawQuad(float width, float height, const AZ::Matrix3x4& transform, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; void DrawSphere(const AZ::Vector3& center, float radius, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; + void DrawHemisphere(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; void DrawDisk(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; void DrawCone(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, float height, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; void DrawCylinder(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, float height, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; + void DrawCylinderNoEnds(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, float height, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; void DrawAabb(const AZ::Aabb& aabb, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; void DrawAabb(const AZ::Aabb& aabb, const AZ::Matrix3x4& transform, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; void DrawObb(const AZ::Obb& obb, const AZ::Vector3& position, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; @@ -73,6 +75,9 @@ namespace AZ private: // functions + void DrawCylinderCommon(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, float height, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex, bool drawEnds); + void DrawSphereCommon(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex, bool isHemisphere); + //! Clear the current buffers void ClearCurrentBufferData(); diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.cpp index c2ee397b4c..2e7c0759db 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.cpp @@ -10,6 +10,7 @@ #include "AuxGeomDrawProcessorShared.h" #include +#include #include #include @@ -69,11 +70,13 @@ namespace AZ SetupInputStreamLayout(m_objectStreamLayout[DrawStyle_Solid], RHI::PrimitiveTopology::TriangleList, false); SetupInputStreamLayout(m_objectStreamLayout[DrawStyle_Shaded], RHI::PrimitiveTopology::TriangleList, true); - CreateSphereBuffersAndViews(); + CreateSphereBuffersAndViews(AuxGeomShapeType::ShapeType_Sphere); + CreateSphereBuffersAndViews(AuxGeomShapeType::ShapeType_Hemisphere); CreateQuadBuffersAndViews(); CreateDiskBuffersAndViews(); CreateConeBuffersAndViews(); - CreateCylinderBuffersAndViews(); + CreateCylinderBuffersAndViews(AuxGeomShapeType::ShapeType_Cylinder); + CreateCylinderBuffersAndViews(AuxGeomShapeType::ShapeType_CylinderNoEnds); CreateBoxBuffersAndViews(); // cache scene pointer for RHI::PipelineState creation. @@ -293,8 +296,11 @@ namespace AZ } } - bool FixedShapeProcessor::CreateSphereBuffersAndViews() + bool FixedShapeProcessor::CreateSphereBuffersAndViews(AuxGeomShapeType sphereShapeType) { + AZ_Assert(sphereShapeType == ShapeType_Sphere || sphereShapeType == ShapeType_Hemisphere, + "Trying to create sphere buffers and views with a non-sphere shape type!"); + const uint32_t numSphereLods = 5; struct LodInfo { @@ -311,13 +317,13 @@ namespace AZ { 9, 9, 0.0000f} }}; - auto& m_shape = m_shapes[ShapeType_Sphere]; + auto& m_shape = m_shapes[sphereShapeType]; m_shape.m_numLods = numSphereLods; for (uint32_t lodIndex = 0; lodIndex < numSphereLods; ++lodIndex) { MeshData meshData; - CreateSphereMeshData(meshData, lodInfo[lodIndex].numRings, lodInfo[lodIndex].numSections); + CreateSphereMeshData(meshData, lodInfo[lodIndex].numRings, lodInfo[lodIndex].numSections, sphereShapeType); ObjectBuffers objectBuffers; @@ -334,12 +340,25 @@ namespace AZ return true; } - void FixedShapeProcessor::CreateSphereMeshData(MeshData& meshData, uint32_t numRings, uint32_t numSections) + void FixedShapeProcessor::CreateSphereMeshData(MeshData& meshData, uint32_t numRings, uint32_t numSections, AuxGeomShapeType sphereShapeType) { const float radius = 1.0f; + // calculate "inner" vertices + float sectionAngle(DegToRad(360.0f / static_cast(numSections))); + float ringSlice(DegToRad(180.0f / static_cast(numRings))); + + uint32_t numberOfPoles = 2; + + if (sphereShapeType == ShapeType_Hemisphere) + { + numberOfPoles = 1; + numRings = (numRings + 1) / 2; + ringSlice = DegToRad(90.0f / static_cast(numRings)); + } + // calc required number of vertices/indices/triangles to build a sphere for the given parameters - uint32_t numVertices = (numRings - 1) * numSections + 2; + uint32_t numVertices = (numRings - 1) * numSections + numberOfPoles; // setup buffers auto& positions = meshData.m_positions; @@ -354,30 +373,29 @@ namespace AZ using NormalType = AuxGeomNormal; // 1st pole vertex - positions.push_back(PosType(0.0f, 0.0f, radius)); - normals.push_back(NormalType(0.0f, 0.0f, 1.0f)); + positions.push_back(PosType(0.0f, radius, 0.0f)); + normals.push_back(NormalType(0.0f, 1.0f, 0.0f)); - // calculate "inner" vertices - float sectionAngle(DegToRad(360.0f / static_cast(numSections))); - float ringSlice(DegToRad(180.0f / static_cast(numRings))); - - for (uint32_t ring = 1; ring < numRings; ++ring) + for (uint32_t ring = 1; ring < numRings - numberOfPoles + 2; ++ring) { float w(sinf(ring * ringSlice)); for (uint32_t section = 0; section < numSections; ++section) { float x = radius * cosf(section * sectionAngle) * w; - float y = radius * sinf(section * sectionAngle) * w; - float z = radius * cosf(ring * ringSlice); + float y = radius * cosf(ring * ringSlice); + float z = radius * sinf(section * sectionAngle) * w; Vector3 radialVector(x, y, z); positions.push_back(radialVector); normals.push_back(radialVector.GetNormalized()); } } - // 2nd vertex of pole (for end cap) - positions.push_back(PosType(0.0f, 0.0f, -radius)); - normals.push_back(NormalType(0.0f, 0.0f, -1.0f)); + if (sphereShapeType == ShapeType_Sphere) + { + // 2nd vertex of pole (for end cap) + positions.push_back(PosType(0.0f, -radius, 0.0f)); + normals.push_back(NormalType(0.0f, -1.0f, 0.0f)); + } // point indices { @@ -393,7 +411,8 @@ namespace AZ // line indices { - const uint32_t numEdges = (numRings - 2) * numSections * 2 + 2 * numSections * 2; + // NumEdges = NumRingEdges + NumSectionEdges = (numRings * numSections) + (numRings * numSections) + const uint32_t numEdges = numRings * numSections * 2; const uint32_t numLineIndices = numEdges * 2; // build "inner" faces @@ -401,10 +420,9 @@ namespace AZ indices.clear(); indices.reserve(numLineIndices); - for (uint16_t ring = 0; ring < numRings - 2; ++ring) + for (uint16_t ring = 0; ring < numRings - numberOfPoles + 1; ++ring) { uint16_t firstVertOfThisRing = static_cast(1 + ring * numSections); - uint16_t firstVertOfNextRing = static_cast(1 + (ring + 1) * numSections); for (uint16_t section = 0; section < numSections; ++section) { uint32_t nextSection = (section + 1) % numSections; @@ -414,32 +432,33 @@ namespace AZ indices.push_back(static_cast(firstVertOfThisRing + nextSection)); // line around section - indices.push_back(firstVertOfThisRing + section); - indices.push_back(firstVertOfNextRing + section); + int currentVertexIndex = firstVertOfThisRing + section; + // max 0 will implicitly handle the top pole + int previousVertexIndex = AZStd::max(currentVertexIndex - (int)numSections, 0); + indices.push_back(static_cast(currentVertexIndex)); + indices.push_back(static_cast(previousVertexIndex)); } } - // build faces for end caps (to connect "inner" vertices with poles) - uint16_t firstPoleVert = 0; - uint16_t firstVertOfFirstRing = static_cast(1 + (0) * numSections); - for (uint16_t section = 0; section < numSections; ++section) - { - indices.push_back(firstPoleVert); - indices.push_back(firstVertOfFirstRing + section); - } - - uint16_t lastPoleVert = static_cast((numRings - 1) * numSections + 1); - uint16_t firstVertOfLastRing = static_cast(1 + (numRings - 2) * numSections); - for (uint16_t section = 0; section < numSections; ++section) + if (sphereShapeType == ShapeType_Sphere) { - indices.push_back(firstVertOfLastRing + section); - indices.push_back(lastPoleVert); + // build faces for bottom pole (to connect "inner" vertices with poles) + uint16_t lastPoleVert = static_cast((numRings - 1) * numSections + 1); + uint16_t firstVertOfLastRing = static_cast(1 + (numRings - 2) * numSections); + for (uint16_t section = 0; section < numSections; ++section) + { + indices.push_back(firstVertOfLastRing + section); + indices.push_back(lastPoleVert); + } } } // triangle indices { - const uint32_t numTriangles = (numRings - 2) * numSections * 2 + 2 * numSections; + // NumTriangles = NumTrianglesAtPoles + NumQuads * 2 + // = (numSections * 2) + ((numRings - 2) * numSections * 2) + // = (numSections * 2) * (numRings - 2 + 1) + const uint32_t numTriangles = (numRings - 1) * numSections * 2; const uint32_t numTriangleIndices = numTriangles * 3; // build "inner" faces @@ -447,10 +466,10 @@ namespace AZ indices.clear(); indices.reserve(numTriangleIndices); - for (uint32_t ring = 0; ring < numRings - 2; ++ring) + for (uint32_t ring = 0; ring < numRings - numberOfPoles; ++ring) { uint32_t firstVertOfThisRing = 1 + ring * numSections; - uint32_t firstVertOfNextRing = 1 + (ring + 1) * numSections; + uint32_t firstVertOfNextRing = firstVertOfThisRing + numSections; for (uint32_t section = 0; section < numSections; ++section) { @@ -476,14 +495,17 @@ namespace AZ indices.push_back(static_cast(firstPoleVert)); } - uint32_t lastPoleVert = (numRings - 1) * numSections + 1; - uint32_t firstVertOfLastRing = 1 + (numRings - 2) * numSections; - for (uint32_t section = 0; section < numSections; ++section) + if (sphereShapeType == ShapeType_Sphere) { - uint32_t nextSection = (section + 1) % numSections; - indices.push_back(static_cast(firstVertOfLastRing + nextSection)); - indices.push_back(static_cast(firstVertOfLastRing + section)); - indices.push_back(static_cast(lastPoleVert)); + uint32_t lastPoleVert = (numRings - 1) * numSections + 1; + uint32_t firstVertOfLastRing = 1 + (numRings - 2) * numSections; + for (uint32_t section = 0; section < numSections; ++section) + { + uint32_t nextSection = (section + 1) % numSections; + indices.push_back(static_cast(firstVertOfLastRing + nextSection)); + indices.push_back(static_cast(firstVertOfLastRing + section)); + indices.push_back(static_cast(lastPoleVert)); + } } } } @@ -827,8 +849,11 @@ namespace AZ } } - bool FixedShapeProcessor::CreateCylinderBuffersAndViews() + bool FixedShapeProcessor::CreateCylinderBuffersAndViews(AuxGeomShapeType cylinderShapeType) { + AZ_Assert(cylinderShapeType == ShapeType_Cylinder || cylinderShapeType == ShapeType_CylinderNoEnds, + "Trying to create cylinder buffers and views with a non-cylinder shape type!"); + const uint32_t numCylinderLods = 5; struct LodInfo { @@ -836,21 +861,21 @@ namespace AZ float screenPercentage; }; const AZStd::array lodInfo = - {{ + { { { 38, 0.1000f}, { 22, 0.0100f}, { 14, 0.0010f}, { 10, 0.0001f}, { 8, 0.0000f} - }}; + } }; - auto& m_shape = m_shapes[ShapeType_Cylinder]; + auto& m_shape = m_shapes[cylinderShapeType]; m_shape.m_numLods = numCylinderLods; for (uint32_t lodIndex = 0; lodIndex < numCylinderLods; ++lodIndex) { MeshData meshData; - CreateCylinderMeshData(meshData, lodInfo[lodIndex].numSections); + CreateCylinderMeshData(meshData, lodInfo[lodIndex].numSections, cylinderShapeType); ObjectBuffers objectBuffers; @@ -867,13 +892,25 @@ namespace AZ return true; } - void FixedShapeProcessor::CreateCylinderMeshData(MeshData& meshData, uint32_t numSections) + void FixedShapeProcessor::CreateCylinderMeshData(MeshData& meshData, uint32_t numSections, AuxGeomShapeType cylinderShapeType) { const float radius = 1.0f; const float height = 1.0f; + //uint16_t indexOfBottomCenter = 0; + //uint16_t indexOfBottomStart = 1; + //uint16_t indexOfTopCenter = numSections + 1; + //uint16_t indexOfTopStart = numSections + 2; + uint16_t indexOfSidesStart = static_cast(2 * numSections + 2); + + if (cylinderShapeType == ShapeType_CylinderNoEnds) + { + // We won't draw disks at the ends of the cylinder, so no need to offset side indices + indexOfSidesStart = 0; + } + // calc required number of vertices to build a cylinder for the given parameters - uint32_t numVertices = 4 * numSections + 2; + uint32_t numVertices = indexOfSidesStart + 2 * numSections; // setup buffers auto& positions = meshData.m_positions; @@ -888,8 +925,11 @@ namespace AZ float topHeight = height * 0.5f; // Create caps - CreateDiskMeshData(meshData, numSections, Facing::Down, bottomHeight); - CreateDiskMeshData(meshData, numSections, Facing::Up, topHeight); + if (cylinderShapeType == ShapeType_Cylinder) + { + CreateDiskMeshData(meshData, numSections, Facing::Down, bottomHeight); + CreateDiskMeshData(meshData, numSections, Facing::Up, topHeight); + } // create vertices for side (so normal points out correctly) float sectionAngle(DegToRad(360.0f / (float)numSections)); @@ -906,12 +946,6 @@ namespace AZ normals.push_back(normal); } - //uint16_t indexOfBottomCenter = 0; - //uint16_t indexOfBottomStart = 1; - //uint16_t indexOfTopCenter = numSections + 1; - //uint16_t indexOfTopStart = numSections + 2; - uint16_t indexOfSidesStart = static_cast(2 * numSections + 2); - // build point indices { auto& indices = meshData.m_pointIndices; @@ -930,6 +964,24 @@ namespace AZ indices.push_back(indexOfSidesStart + 2 * section); indices.push_back(indexOfSidesStart + 2 * section + 1); } + + // If we're not drawing the disks at the ends of the cylinder, we still want to + // draw a ring around the end to join the tips of lines we created just above + if (cylinderShapeType == ShapeType_CylinderNoEnds) + { + for (uint16_t section = 0; section < numSections; ++section) + { + uint16_t nextSection = (section + 1) % numSections; + + // line around the bottom cap + indices.push_back(section * 2); + indices.push_back(nextSection * 2); + + // line around the top cap + indices.push_back(section * 2 + 1); + indices.push_back(nextSection * 2 + 1); + } + } } // indices for triangles diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.h b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.h index 4007d62f66..958cee3143 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.h @@ -138,8 +138,8 @@ namespace AZ Both, }; - bool CreateSphereBuffersAndViews(); - void CreateSphereMeshData(MeshData& meshData, uint32_t numRings, uint32_t numSections); + bool CreateSphereBuffersAndViews(AuxGeomShapeType sphereShapeType); + void CreateSphereMeshData(MeshData& meshData, uint32_t numRings, uint32_t numSections, AuxGeomShapeType sphereShapeType); bool CreateQuadBuffersAndViews(); void CreateQuadMeshDataSide(MeshData& meshData, bool isUp, bool drawLines); @@ -152,8 +152,8 @@ namespace AZ bool CreateConeBuffersAndViews(); void CreateConeMeshData(MeshData& meshData, uint32_t numRings, uint32_t numSections); - bool CreateCylinderBuffersAndViews(); - void CreateCylinderMeshData(MeshData& meshData, uint32_t numSections); + bool CreateCylinderBuffersAndViews(AuxGeomShapeType cylinderShapeType); + void CreateCylinderMeshData(MeshData& meshData, uint32_t numSections, AuxGeomShapeType cylinderShapeType); bool CreateBoxBuffersAndViews(); void CreateBoxMeshData(MeshData& meshData); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h index 474d0d5b9e..d6d2352097 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h @@ -147,6 +147,17 @@ namespace AZ //! @param viewProjOverrideIndex Which view projection override entry to use, -1 if unused virtual void DrawSphere( const AZ::Vector3& center, float radius, const AZ::Color& color, DrawStyle style = DrawStyle::Shaded, DepthTest depthTest = DepthTest::On, DepthWrite depthWrite = DepthWrite::On, FaceCullMode faceCull = FaceCullMode::Back, int32_t viewProjOverrideIndex = -1) = 0; + //! Draw a hemisphere. + //! @param center The center of the sphere. + //! @param radius The radius. + //! @param color The color to draw the sphere. + //! @param style The draw style (point, wireframe, solid, shaded etc). + //! @param depthTest If depth testing should be enabled + //! @param depthWrite If depth writing should be enabled + //! @param faceCull Which (if any) facing triangles should be culled + //! @param viewProjOverrideIndex Which view projection override entry to use, -1 if unused + virtual void DrawHemisphere( const AZ::Vector3& center, const AZ::Vector3& direction, float radius, const AZ::Color& color, DrawStyle style = DrawStyle::Shaded, DepthTest depthTest = DepthTest::On, DepthWrite depthWrite = DepthWrite::On, FaceCullMode faceCull = FaceCullMode::Back, int32_t viewProjOverrideIndex = -1) = 0; + //! Draw a disk. //! @param center The center of the disk. //! @param direction The direction vector. The disk will be orthogonal this vector. @@ -172,7 +183,7 @@ namespace AZ //! @param viewProjOverrideIndex Which view projection override entry to use, -1 if unused virtual void DrawCone(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, float height, const AZ::Color& color, DrawStyle style = DrawStyle::Shaded, DepthTest depthTest = DepthTest::On, DepthWrite depthWrite = DepthWrite::On, FaceCullMode faceCull = FaceCullMode::Back, int32_t viewProjOverrideIndex = -1) = 0; - //! Draw a cylinder. + //! Draw a cylinder (with flat disks on the end). //! @param center The center of the base circle. //! @param direction The direction vector. The top end cap of the cylinder will face along this vector. //! @param radius The radius. @@ -185,6 +196,19 @@ namespace AZ //! @param viewProjOverrideIndex Which view projection override entry to use, -1 if unused virtual void DrawCylinder(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, float height, const AZ::Color& color, DrawStyle style = DrawStyle::Shaded, DepthTest depthTest = DepthTest::On, DepthWrite depthWrite = DepthWrite::On, FaceCullMode faceCull = FaceCullMode::Back, int32_t viewProjOverrideIndex = -1) = 0; + //! Draw a cylinder without flat disk on the end. + //! @param center The center of the base circle. + //! @param direction The direction vector. The top end cap of the cylinder will face along this vector. + //! @param radius The radius. + //! @param height The height of the cylinder. + //! @param color The color to draw the cylinder. + //! @param style The draw style (point, wireframe, solid, shaded etc). + //! @param depthTest If depth testing should be enabled + //! @param depthWrite If depth writing should be enabled + //! @param faceCull Which (if any) facing triangles should be culled + //! @param viewProjOverrideIndex Which view projection override entry to use, -1 if unused + virtual void DrawCylinderNoEnds(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, float height, const AZ::Color& color, DrawStyle style = DrawStyle::Shaded, DepthTest depthTest = DepthTest::On, DepthWrite depthWrite = DepthWrite::On, FaceCullMode faceCull = FaceCullMode::Back, int32_t viewProjOverrideIndex = -1) = 0; + //! Draw an axis-aligned bounding box with no transform. //! @param aabb The AABB (typically the bounding box of a set of world space points). //! @param color The color to draw the box. diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp index e2d99dbbef..b72a19c311 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp @@ -1025,83 +1025,57 @@ namespace AZ::AtomBridge if (m_auxGeomPtr && radius > FLT_EPSILON && axis.GetLengthSq() > FLT_EPSILON) { AZ::Vector3 axisNormalized = axis.GetNormalizedEstimate(); - SingleColorStaticSizeLineHelper<(16+1) * 5> lines; // 360/22.5 = 16, 5 possible calls to CreateArbitraryAxisArc - AZ::Vector3 radiusV3 = AZ::Vector3(radius); - float stepAngle = DegToRad(22.5f); - float Deg0 = DegToRad(0.0f); + const float scale = GetCurrentTransform().RetrieveScale().GetMaxElement(); + const AZ::Vector3 worldCenter = ToWorldSpacePosition(center); + const AZ::Vector3 worldAxis = ToWorldSpaceVector(axis); // Draw cylinder part (or just a circle around the middle) if (heightStraightSection > FLT_EPSILON) { - DrawWireCylinder(center, axis, radius, heightStraightSection); - } - else - { - float Deg360 = DegToRad(360.0f); - CreateArbitraryAxisArc( - lines, - stepAngle, - Deg0, - Deg360, - center, - radiusV3, - axisNormalized - ); + m_auxGeomPtr->DrawCylinderNoEnds( + worldCenter, + worldAxis, + scale * radius, + scale * heightStraightSection, + m_rendState.m_color, + AZ::RPI::AuxGeomDraw::DrawStyle::Line, + m_rendState.m_depthTest, + m_rendState.m_depthWrite, + m_rendState.m_faceCullMode, + m_rendState.m_viewProjOverrideIndex + ); } - float Deg90 = DegToRad(90.0f); - float Deg180 = DegToRad(180.0f); - AZ::Vector3 ortho1Normalized, ortho2Normalized; CalcBasisVectors(axisNormalized, ortho1Normalized, ortho2Normalized); AZ::Vector3 centerToTopCircleCenter = axisNormalized * heightStraightSection * 0.5f; AZ::Vector3 topCenter = center + centerToTopCircleCenter; AZ::Vector3 bottomCenter = center - centerToTopCircleCenter; - // Draw top cap as two criss-crossing 180deg arcs - CreateArbitraryAxisArc( - lines, - stepAngle, - Deg90, - Deg90 + Deg180, - topCenter, - radiusV3, - ortho1Normalized - ); - - CreateArbitraryAxisArc( - lines, - stepAngle, - Deg180, - Deg180 + Deg180, - topCenter, - radiusV3, - ortho2Normalized - ); - - // Draw bottom cap - CreateArbitraryAxisArc( - lines, - stepAngle, - -Deg90, - -Deg90 + Deg180, - bottomCenter, - radiusV3, - ortho1Normalized - ); - - CreateArbitraryAxisArc( - lines, - stepAngle, - Deg0, - Deg0 + Deg180, - bottomCenter, - radiusV3, - ortho2Normalized - ); + m_auxGeomPtr->DrawHemisphere( + topCenter, + worldAxis, + scale * radius, + m_rendState.m_color, + AZ::RPI::AuxGeomDraw::DrawStyle::Line, + m_rendState.m_depthTest, + m_rendState.m_depthWrite, + m_rendState.m_faceCullMode, + m_rendState.m_viewProjOverrideIndex + ); - lines.Draw(m_auxGeomPtr, m_rendState); + m_auxGeomPtr->DrawHemisphere( + bottomCenter, + -worldAxis, + scale * radius, + m_rendState.m_color, + AZ::RPI::AuxGeomDraw::DrawStyle::Line, + m_rendState.m_depthTest, + m_rendState.m_depthWrite, + m_rendState.m_faceCullMode, + m_rendState.m_viewProjOverrideIndex + ); } }