void FConstraintComponentVisualizer::DrawVisualization( const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI )
{
	const UPhysicsConstraintComponent* ConstraintComp = Cast<const UPhysicsConstraintComponent>(Component);
	if(ConstraintComp != NULL)
	{
		const FConstraintInstance& Instance = ConstraintComp->ConstraintInstance;

		FTransform Con1Frame, Con2Frame;

		// If constraint is created, use the calculated frame
		if(Instance.IsValidConstraintInstance())
		{
			FTransform BodyTransform1 = ConstraintComp->GetBodyTransform(EConstraintFrame::Frame1);
			BodyTransform1.RemoveScaling();
			FTransform BodyTransform2 = ConstraintComp->GetBodyTransform(EConstraintFrame::Frame2);
			BodyTransform2.RemoveScaling();

			Con1Frame = Instance.GetRefFrame(EConstraintFrame::Frame1) * BodyTransform1;
			Con2Frame = Instance.GetRefFrame(EConstraintFrame::Frame2) * BodyTransform2;
		}
		// Otherwise use the component frame
		else
		{
			Con1Frame = ConstraintComp->ComponentToWorld;
			Con1Frame.RemoveScaling();
			Con2Frame = ConstraintComp->ComponentToWorld;
			Con2Frame.SetRotation(ConstraintComp->ConstraintInstance.AngularRotationOffset.Quaternion() * Con2Frame.GetRotation());
			Con1Frame.RemoveScaling();
		}

		FBox Body1Box = ConstraintComp->GetBodyBox(EConstraintFrame::Frame1);
		FBox Body2Box = ConstraintComp->GetBodyBox(EConstraintFrame::Frame2);

		// Draw constraint information
		Instance.DrawConstraint(PDI, 1.f, 1.f, true, true, Con1Frame, Con2Frame, false);

		// Draw boxes to indicate bodies connected by joint.
		if(Body1Box.IsValid)
		{
			PDI->DrawLine( Con1Frame.GetTranslation(), Body1Box.GetCenter(), JointFrame1Color, SDPG_World );
			DrawWireBox(PDI, Body1Box, JointFrame1Color, SDPG_World );
		}

		if(Body2Box.IsValid)
		{
			PDI->DrawLine( Con2Frame.GetTranslation(), Body2Box.GetCenter(), JointFrame2Color, SDPG_World );
			DrawWireBox(PDI, Body2Box, JointFrame2Color, SDPG_World );
		}
	}
}
Пример #2
0
void DrawWireBox(NxShape* box, const NxVec3& color, float lineWidth)
{
	NxBox obb;
	box->isBox()->getWorldOBB(obb);

	DrawWireBox(obb, color, lineWidth);
}
Пример #3
0
void DrawWireShape(NxShape *shape, const NxVec3& color)
{
    switch(shape->getType())
    {
		case NX_SHAPE_PLANE:
			DrawWirePlane(shape, color);
		break;
		case NX_SHAPE_BOX:
			DrawWireBox(shape, color);
		break;
		case NX_SHAPE_SPHERE:
			DrawWireSphere(shape, color);
		break;
		case NX_SHAPE_CAPSULE:
			DrawWireCapsule(shape, color);
		break;
		case NX_SHAPE_CONVEX:
			DrawWireConvex(shape, color);
		break;		
		case NX_SHAPE_MESH:
			DrawWireMesh(shape, color);
		break;
		default:
		break;
	}
}
Пример #4
0
    void BufferedPrimitiveRenderer::DrawWireBox(const BoundingBox& bbox,
        const Matrix& transform,
        const Color& color /*= DefaultColor*/,
        DebugLifespan::Enum lifespan /*= DebugLifespan::Temporary*/,
        bool depthEnabled /*= false*/, 
        bool antiAliased /*= false*/) {

        Vector3f min = bbox.GetMin();
        Vector3f max = bbox.GetMax();
        Vector3f translation = (min + max) / 2.0f;
        Vector3f scale(max.x - min.x, max.y - min.y, max.z - min.z);
        Matrix newTransform = Matrix::CreateScale(scale) * Matrix::CreateTranslation(translation) * transform;
        DrawWireBox(newTransform, color, lifespan, depthEnabled, antiAliased);
    }
void FDestructibleMeshEditorViewportClient::Draw( const FSceneView* View,FPrimitiveDrawInterface* PDI )
{
	FEditorViewportClient::Draw(View, PDI);

#if WITH_APEX
	const bool DrawChunkMarker = true;

	UDestructibleComponent* Comp = PreviewDestructibleComp.Get();
	
	if (Comp)
	{
		if (Comp->DestructibleMesh != NULL && Comp->DestructibleMesh->FractureSettings != NULL)
		{
			if (Comp->DestructibleMesh->ApexDestructibleAsset != NULL)
			{
				NxDestructibleAsset* Asset = Comp->DestructibleMesh->ApexDestructibleAsset;
				const NxRenderMeshAsset* RenderMesh = Asset->getRenderMeshAsset();

				for (uint32 i=0; i < Asset->getChunkCount(); ++i)
				{
					int32 PartIdx = Asset->getPartIndex(i);
					int32 BoneIdx = i+1;

					if ( SelectedChunkIndices.Contains(i) )
					{
						PxBounds3 PBounds = RenderMesh->getBounds(PartIdx);

						FVector Center = P2UVector(PBounds.getCenter()) + Comp->GetBoneLocation(Comp->GetBoneName(BoneIdx));
						FVector Extent = P2UVector(PBounds.getExtents());

						FBox Bounds(Center - Extent, Center + Extent);
						DrawWireBox(PDI, Bounds, FColor::Blue, SDPG_World);
					}
				}
			}
		}
	}
#endif // WITH_APEX
}
Пример #6
0
    void BufferedPrimitiveRenderer::DrawWireBox(const Vector3f& center,
                                            F32 width,
                                            F32 height,
                                            F32 depth,
                                            const Vector3f& forward,
                                            const Vector3f& up,
                                            const Color& color /*= DefaultColor*/,
                                            DebugLifespan::Enum lifespan /*= DebugLifespan::Temporary*/,
                                            bool depthEnabled /*= false*/,
                                            bool antiAliased /*= false*/) {

        Vector3f direction = Vector3f::Normalize(up);
        F32 roll = (F32) atan2(direction.x, direction.y);
        F32 yaw = (F32) asin(direction.z);
        Quaternion rotQuat = Quaternion::CreateFromRollPitchYaw(0, yaw, roll);
        Matrix rot = Matrix::CreateFromQuaternion(rotQuat);
        Vector3f rotForward = Vector3f::TransformVector(Vector3f::UnitZ, rot);
        Vector3f orthoForward(rotForward.x, rotForward.z, rotForward.y);
        F32 angle = Vector3f::AngleSigned(rotForward, forward, orthoForward);
        Matrix forwardRotation = Matrix::CreateRotationAxis(orthoForward, angle);
        Matrix transform = Matrix::CreateScale(width, height, depth) * (rot * forwardRotation) * Matrix::CreateTranslation(center);

        DrawWireBox(transform, color, lifespan, depthEnabled, antiAliased);
    }
void FStereoLayerComponentVisualizer::DrawVisualization( const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI )
{
	const UStereoLayerComponent* StereoLayerComp = Cast<const UStereoLayerComponent>(Component);
	if(StereoLayerComp != NULL)
	{
        FLinearColor YellowColor = FColor(231, 239, 0, 255);
        if(StereoLayerComp->StereoLayerShape == EStereoLayerShape::SLSH_QuadLayer)
        {
            const FVector2D QuadSize = StereoLayerComp->GetQuadSize() / 2.0f;
            const FBox QuadBox(FVector(0.0f, -QuadSize.X, -QuadSize.Y), FVector(0.0f, QuadSize.X, QuadSize.Y));

            DrawWireBox(PDI, StereoLayerComp->ComponentToWorld.ToMatrixWithScale(), QuadBox, YellowColor, 0);
        }
        else if(StereoLayerComp->StereoLayerShape == EStereoLayerShape::SLSH_CylinderLayer)
        {
            float ArcAngle = StereoLayerComp->CylinderOverlayArc * 180 / (StereoLayerComp->CylinderRadius * PI);
            
            FVector X = StereoLayerComp->ComponentToWorld.GetUnitAxis(EAxis::Type::X);
            FVector Y = StereoLayerComp->ComponentToWorld.GetUnitAxis(EAxis::Type::Y);
            FVector Base = StereoLayerComp->ComponentToWorld.GetLocation();
            FVector HalfHeight = FVector(0, 0, StereoLayerComp->CylinderHeight/2);
            
            FVector LeftVertex = Base + StereoLayerComp->CylinderRadius * ( FMath::Cos(ArcAngle/2 * (PI/180.0f)) * X + FMath::Sin(ArcAngle/2 * (PI/180.0f)) * Y );
            FVector RightVertex = Base + StereoLayerComp->CylinderRadius * ( FMath::Cos(-ArcAngle/2 * (PI/180.0f)) * X + FMath::Sin(-ArcAngle/2 * (PI/180.0f)) * Y );

            DrawArc(PDI, Base + HalfHeight, X, Y, -ArcAngle/2, ArcAngle/2, StereoLayerComp->CylinderRadius, 10, YellowColor, 0);
            
            DrawArc(PDI, Base - HalfHeight, X, Y, -ArcAngle/2, ArcAngle/2, StereoLayerComp->CylinderRadius, 10, YellowColor, 0);

            PDI->DrawLine( LeftVertex - HalfHeight, LeftVertex + HalfHeight, YellowColor, 0 );
            
            PDI->DrawLine( RightVertex - HalfHeight, RightVertex + HalfHeight, YellowColor, 0 );

        }
    }
}
Пример #8
0
void FEditorCommonDrawHelper::DrawOldGrid(const FSceneView* View,FPrimitiveDrawInterface* PDI)
{
	ESceneDepthPriorityGroup eDPG = (ESceneDepthPriorityGroup)DepthPriorityGroup;

	bool bIsPerspective = ( View->ViewMatrices.ProjMatrix.M[3][3] < 1.0f );

	// Draw 3D perspective grid
	if( bIsPerspective)
	{
		// @todo: Persp grid should be changed to be adaptive and use same settings as ortho grid, including grid interval!
		const int32 RangeInCells = NumCells / 2;
		const int32 MajorLineInterval = NumCells / 8;

		const int32 NumLines = NumCells + 1;
		const int32 AxesIndex = NumCells / 2;
		for( int32 LineIndex = 0; LineIndex < NumLines; ++LineIndex )
		{
			bool bIsMajorLine = ( ( LineIndex - RangeInCells ) % MajorLineInterval ) == 0;

			FVector A,B;
			A.X=(PerspectiveGridSize/4.f)*(-1.0+2.0*LineIndex/NumCells);	B.X=A.X;

			A.Y=(PerspectiveGridSize/4.f);		B.Y=-(PerspectiveGridSize/4.f);
			A.Z=0.0;							B.Z=0.0;

			FColor LineColor;
			float LineThickness = 0.f;

			if ( LineIndex==AxesIndex )
			{
				LineColor = GridColorAxis;
				LineThickness = AxesLineThickness;
			}
			else if ( bIsMajorLine )
			{
				LineColor = GridColorMajor;
			}
			else
			{
				LineColor = GridColorMinor;
			}

			PDI->DrawLine(A,B,LineColor,eDPG, LineThickness, GridDepthBias);

			A.Y=A.X;							B.Y=B.X;
			A.X=(PerspectiveGridSize/4.f);		B.X=-(PerspectiveGridSize/4.f);
			PDI->DrawLine(A,B,LineColor,eDPG, LineThickness, GridDepthBias);
		}
	}
	// Draw ortho grid.
	else
	{
		const bool bIsOrthoXY = ( FMath::Abs(View->ViewMatrices.ViewMatrix.M[2][2]) > 0.0f );
		const bool bIsOrthoXZ = ( FMath::Abs(View->ViewMatrices.ViewMatrix.M[1][2]) > 0.0f );
		const bool bIsOrthoYZ = ( FMath::Abs(View->ViewMatrices.ViewMatrix.M[0][2]) > 0.0f );

		FLinearColor AxisColors[3];
		GetAxisColors(AxisColors, false);

		if( bIsOrthoXY )
		{
			FVector StartY( 0.0f, +HALF_WORLD_MAX1, -HALF_WORLD_MAX );
			FVector EndY( 0.0f, -HALF_WORLD_MAX1, -HALF_WORLD_MAX );
			FVector StartX( +HALF_WORLD_MAX1, 0.0f, -HALF_WORLD_MAX );
			FVector EndX( -HALF_WORLD_MAX1, 0.0f, -HALF_WORLD_MAX );
			DrawGridSection( GEditor->GetGridSize(), &StartY, &EndY, &StartY.X, &EndY.X, 0, View, PDI);
			DrawGridSection( GEditor->GetGridSize(), &StartX, &EndX, &StartX.Y, &EndX.Y, 1, View, PDI);
			DrawOriginAxisLine( &StartY, &EndY, &StartY.X, &EndY.X, View, PDI, AxisColors[1] );
			DrawOriginAxisLine( &StartX, &EndX, &StartX.Y, &EndX.Y, View, PDI, AxisColors[0] );
		}
		else if( bIsOrthoXZ )
		{
			FVector StartZ( 0.0f, -HALF_WORLD_MAX, +HALF_WORLD_MAX1 );
			FVector EndZ( 0.0f, -HALF_WORLD_MAX, -HALF_WORLD_MAX1 );
			FVector StartX( +HALF_WORLD_MAX1, -HALF_WORLD_MAX, 0.0f );
			FVector EndX( -HALF_WORLD_MAX1, -HALF_WORLD_MAX, 0.0f );
			DrawGridSection( GEditor->GetGridSize(), &StartZ, &EndZ, &StartZ.X, &EndZ.X, 0, View, PDI);
			DrawGridSection( GEditor->GetGridSize(), &StartX, &EndX, &StartX.Z, &EndX.Z, 2, View, PDI);
			DrawOriginAxisLine( &StartZ, &EndZ, &StartZ.X, &EndZ.X, View, PDI, AxisColors[2] );
			DrawOriginAxisLine( &StartX, &EndX, &StartX.Z, &EndX.Z, View, PDI, AxisColors[0] );
		}
		else if( bIsOrthoYZ )
		{
			FVector StartZ( +HALF_WORLD_MAX, 0.0f, +HALF_WORLD_MAX1 );
			FVector EndZ( +HALF_WORLD_MAX, 0.0f, -HALF_WORLD_MAX1 );
			FVector StartY( +HALF_WORLD_MAX, +HALF_WORLD_MAX1, 0.0f );
			FVector EndY( +HALF_WORLD_MAX, -HALF_WORLD_MAX1, 0.0f );
			DrawGridSection( GEditor->GetGridSize(), &StartZ, &EndZ, &StartZ.Y, &EndZ.Y, 1, View, PDI);
			DrawGridSection( GEditor->GetGridSize(), &StartY, &EndY, &StartY.Z, &EndY.Z, 2, View, PDI);
			DrawOriginAxisLine( &StartZ, &EndZ, &StartZ.Y, &EndZ.Y, View, PDI, AxisColors[2] );
			DrawOriginAxisLine( &StartY, &EndY, &StartY.Z, &EndY.Z, View, PDI, AxisColors[1] );
		}

		if( bDrawKillZ && ( bIsOrthoXZ || bIsOrthoYZ ) && GWorld->GetWorldSettings()->bEnableWorldBoundsChecks )
		{
			float KillZ = GWorld->GetWorldSettings()->KillZ;

			PDI->DrawLine( FVector(-HALF_WORLD_MAX,0,KillZ), FVector(HALF_WORLD_MAX,0,KillZ), FColor(255,0,0), SDPG_Foreground );
			PDI->DrawLine( FVector(0,-HALF_WORLD_MAX,KillZ), FVector(0,HALF_WORLD_MAX,KillZ), FColor(255,0,0), SDPG_Foreground );
		}
	}

	// Draw orthogonal worldframe.
	if(bDrawWorldBox)
	{
		DrawWireBox(PDI, FBox( FVector(-HALF_WORLD_MAX1,-HALF_WORLD_MAX1,-HALF_WORLD_MAX1),FVector(HALF_WORLD_MAX1,HALF_WORLD_MAX1,HALF_WORLD_MAX1) ), GEngine->C_WorldBox, eDPG );
	}
}
Пример #9
0
void Update()
{
	NxMat34 mat34;
	NxMat33 mat;
	NxQuat quat(0.0f,NxVec3(0,1,0));  
	mat.fromQuat(quat);
	NxBox worldBox;
	worldBox.extents	= NxVec3(2, 2, 2);
	worldBox.rot		= mat;

	NxSphere	worldSphere;
	NxBounds3	worldBounds;
	NxCapsule	worldCapsule;
	worldCapsule.radius = 2.0f;

	NxU32 nbPlanes = 2;
	NxPlane worldPlanes[2];
	worldPlanes[0].set(NxVec3(-2,0,2), NxVec3(0,0,1));
	worldPlanes[1].set(NxVec3(-2,0,2), NxVec3(1,0,0));

	NxU32 nbDynamicShapes	= gScene->getNbDynamicShapes();
	NxU32 nbStaticShapes	= gScene->getNbStaticShapes();
	NxU32 nbShapes = 0;
	NxShapesType type;

	int i = 0;
	for (i = 0; i < 3; ++ i)
	{
		if (i == 0)
		{
			nbShapes = nbDynamicShapes;
			type	 = NX_DYNAMIC_SHAPES;
			switch(gOverlapType)
			{
			case OVERLAP_AABB:
			case OVERLAP_CHECK_AABB:
				worldBounds.set(gMIN, gMAX);
				break;
			case OVERLAP_OBB:
			case OVERLAP_CHECK_OBB:
				worldBox.center = gBoxCenter;
				break;
			case OVERLAP_CAPSULE:
			case OVERLAP_CHECK_CAPSULE:
				worldCapsule = NxCapsule(gCapsuleSegment, gCapsuleRadius);
				break;
			case OVERLAP_SPHERE:
			case OVERLAP_CHECK_SPHERE:
				worldSphere = NxSphere(gSphereCenter, gSphereRadius);
				break;
			}
		}
		else if (i == 1)
		{
			nbShapes = nbStaticShapes;
			type	 = NX_STATIC_SHAPES;
			switch(gOverlapType)
			{
			case OVERLAP_AABB:
			case OVERLAP_CHECK_AABB:
				worldBounds.set(gMIN+NxVec3(-6.0f,0,0),gMAX+NxVec3(-6.0f,0,0));
				break;
			case OVERLAP_OBB:
			case OVERLAP_CHECK_OBB:
				worldBox.center = gBoxCenter+NxVec3(-6,0,0);
				break;
			case OVERLAP_CAPSULE:
			case OVERLAP_CHECK_CAPSULE:
				worldCapsule.p0.x = gCapsuleSegment.p0.x - 6.0f;
				worldCapsule.p1.x = gCapsuleSegment.p1.x - 6.0f;
				break;
			case OVERLAP_SPHERE:
			case OVERLAP_CHECK_SPHERE:
				worldSphere = NxSphere(gSphereCenter + NxVec3(-6,0,0), gSphereRadius);
				break;
			}
		}
		else if (i == 2)
		{
			nbShapes = nbStaticShapes + nbDynamicShapes;
			type	 = NX_ALL_SHAPES;
			switch(gOverlapType)
			{
			case OVERLAP_AABB:
			case OVERLAP_CHECK_AABB:
				worldBounds.set(gMIN+NxVec3(6.0f,0,0),gMAX+NxVec3(6.0f,0,0));
				break;
			case OVERLAP_OBB:
			case OVERLAP_CHECK_OBB:
				worldBox.center = gBoxCenter+NxVec3(6,0,0);
				break;
			case OVERLAP_CAPSULE:
			case OVERLAP_CHECK_CAPSULE:
				worldCapsule.p0.x = gCapsuleSegment.p0.x + 6.0f;
				worldCapsule.p1.x = gCapsuleSegment.p1.x + 6.0f;
				break;
			case OVERLAP_SPHERE:
			case OVERLAP_CHECK_SPHERE:
				worldSphere = NxSphere(gSphereCenter + NxVec3(6,0,0), gSphereRadius);
				break;
			}
		}

		NxShape** shapes = (NxShape**)NxAlloca(nbShapes*sizeof(NxShape*));
		for (NxU32 j = 0; j < nbShapes; j++)  shapes[j] = NULL;
		NxU32 activeGroups = 0xffffffff;
		NxGroupsMask* groupsMask = NULL;
		bool bResult	= true;
		float linewidth = 1.0f;
		switch(gOverlapType)
		{
		case OVERLAP_AABB:
			gScene->overlapAABBShapes(worldBounds, type, nbShapes, shapes, &gShapeReport, activeGroups, groupsMask, true);
			NxCreateBox(worldBox, worldBounds, mat34);
			DrawWireBox(worldBox, NxVec3(1,0,0), linewidth);
			break;
		case OVERLAP_CHECK_AABB:
			bResult = gScene->checkOverlapAABB(worldBounds, type, activeGroups, groupsMask);
			NxCreateBox(worldBox, worldBounds, mat34);
			if (bResult == true)
				DrawWireBox(worldBox, NxVec3(1,0,0), linewidth);
			else
				DrawWireBox(worldBox, NxVec3(0,1,0), linewidth);
			break;
		case OVERLAP_OBB:
			gScene->overlapOBBShapes(worldBox, type, nbShapes, shapes, &gShapeReport, activeGroups, groupsMask);
			DrawWireBox(worldBox, NxVec3(1,0,0), linewidth);
			break;
		case OVERLAP_CHECK_OBB:
			if (gScene->checkOverlapOBB(worldBox, type, activeGroups, groupsMask) == true)
				DrawWireBox(worldBox, NxVec3(1,0,0), linewidth);
			else
				DrawWireBox(worldBox, NxVec3(0,1,0), linewidth);
			break;
		case OVERLAP_CAPSULE:
			gScene->overlapCapsuleShapes(worldCapsule, type, nbShapes, shapes, &gShapeReport, activeGroups, groupsMask);
			DrawWireCapsule(worldCapsule, NxVec3(1,0,0));
			break;
		case OVERLAP_CHECK_CAPSULE:
			if (gScene->checkOverlapCapsule(worldCapsule, type,activeGroups, groupsMask) == true)
				DrawWireCapsule(worldCapsule, NxVec3(1,0,0));
			else
				DrawWireCapsule(worldCapsule, NxVec3(0,1,0));
			break;
		case OVERLAP_SPHERE:
			gScene->overlapSphereShapes(worldSphere, type, nbShapes, shapes, &gShapeReport, activeGroups, groupsMask);
			DrawWireSphere(&worldSphere, NxVec3(1,0,0));
			break;
		case OVERLAP_CHECK_SPHERE:
			if (gScene->checkOverlapSphere(worldSphere, type,activeGroups, groupsMask) == true)
				DrawWireSphere(&worldSphere, NxVec3(1,0,0));
			else
				DrawWireSphere(&worldSphere, NxVec3(0,1,0));
			break;
		case OVERLAP_CULL:
			gScene->cullShapes(nbPlanes, worldPlanes, type, nbShapes, shapes, &gShapeReport, activeGroups, groupsMask);
			DrawLine(NxVec3(-20,0,2), NxVec3(-2,0,2),NxVec3(1,0,0), linewidth);
			DrawLine(NxVec3(-2,0,-20), NxVec3(-2,0,2),NxVec3(1,0,0), linewidth);
			break;
		}
	}
}
Пример #10
0
/** 
 * Returns an array of visibility data for the given view position, or NULL if none exists. 
 * The data bits are indexed by VisibilityId of each primitive in the scene.
 * This method decompresses data if necessary and caches it based on the bucket and chunk index in the view state.
 */
const uint8* FSceneViewState::GetPrecomputedVisibilityData(FViewInfo& View, const FScene* Scene)
{
	const uint8* PrecomputedVisibilityData = NULL;
	if (Scene->PrecomputedVisibilityHandler && GAllowPrecomputedVisibility && View.Family->EngineShowFlags.PrecomputedVisibility)
	{
		const FPrecomputedVisibilityHandler& Handler = *Scene->PrecomputedVisibilityHandler;
		FViewElementPDI VisibilityCellsPDI(&View, NULL);

		// Draw visibility cell bounds for debugging if enabled
		if ((GShowPrecomputedVisibilityCells || View.Family->EngineShowFlags.PrecomputedVisibilityCells) && !GShowRelevantPrecomputedVisibilityCells)
		{
			for (int32 BucketIndex = 0; BucketIndex < Handler.PrecomputedVisibilityCellBuckets.Num(); BucketIndex++)
			{
				for (int32 CellIndex = 0; CellIndex < Handler.PrecomputedVisibilityCellBuckets[BucketIndex].Cells.Num(); CellIndex++)
				{
					const FPrecomputedVisibilityCell& CurrentCell = Handler.PrecomputedVisibilityCellBuckets[BucketIndex].Cells[CellIndex];
					// Construct the cell's bounds
					const FBox CellBounds(CurrentCell.Min, CurrentCell.Min + FVector(Handler.PrecomputedVisibilityCellSizeXY, Handler.PrecomputedVisibilityCellSizeXY, Handler.PrecomputedVisibilityCellSizeZ));
					if (View.ViewFrustum.IntersectBox(CellBounds.GetCenter(), CellBounds.GetExtent()))
					{
						DrawWireBox(&VisibilityCellsPDI, CellBounds, FColor(50, 50, 255), SDPG_World);
					}
				}
			}
		}

		// Calculate the bucket that ViewOrigin falls into
		// Cells are hashed into buckets to reduce search time
		const float FloatOffsetX = (View.ViewMatrices.ViewOrigin.X - Handler.PrecomputedVisibilityCellBucketOriginXY.X) / Handler.PrecomputedVisibilityCellSizeXY;
		// FMath::TruncToInt rounds toward 0, we want to always round down
		const int32 BucketIndexX = FMath::Abs((FMath::TruncToInt(FloatOffsetX) - (FloatOffsetX < 0.0f ? 1 : 0)) / Handler.PrecomputedVisibilityCellBucketSizeXY % Handler.PrecomputedVisibilityNumCellBuckets);
		const float FloatOffsetY = (View.ViewMatrices.ViewOrigin.Y -Handler.PrecomputedVisibilityCellBucketOriginXY.Y) / Handler.PrecomputedVisibilityCellSizeXY;
		const int32 BucketIndexY = FMath::Abs((FMath::TruncToInt(FloatOffsetY) - (FloatOffsetY < 0.0f ? 1 : 0)) / Handler.PrecomputedVisibilityCellBucketSizeXY % Handler.PrecomputedVisibilityNumCellBuckets);
		const int32 PrecomputedVisibilityBucketIndex = BucketIndexY * Handler.PrecomputedVisibilityCellBucketSizeXY + BucketIndexX;

		check(PrecomputedVisibilityBucketIndex < Handler.PrecomputedVisibilityCellBuckets.Num());
		const FPrecomputedVisibilityBucket& CurrentBucket = Handler.PrecomputedVisibilityCellBuckets[PrecomputedVisibilityBucketIndex];
		for (int32 CellIndex = 0; CellIndex < CurrentBucket.Cells.Num(); CellIndex++)
		{
			const FPrecomputedVisibilityCell& CurrentCell = CurrentBucket.Cells[CellIndex];
			// Construct the cell's bounds
			const FBox CellBounds(CurrentCell.Min, CurrentCell.Min + FVector(Handler.PrecomputedVisibilityCellSizeXY, Handler.PrecomputedVisibilityCellSizeXY, Handler.PrecomputedVisibilityCellSizeZ));
			// Check if ViewOrigin is inside the current cell
			if (CellBounds.IsInside(View.ViewMatrices.ViewOrigin))
			{
				// Reuse a cached decompressed chunk if possible
				if (CachedVisibilityChunk
					&& CachedVisibilityHandlerId == Scene->PrecomputedVisibilityHandler->GetId()
					&& CachedVisibilityBucketIndex == PrecomputedVisibilityBucketIndex
					&& CachedVisibilityChunkIndex == CurrentCell.ChunkIndex)
				{
					checkSlow(CachedVisibilityChunk->Num() >= CurrentCell.DataOffset + CurrentBucket.CellDataSize);
					PrecomputedVisibilityData = &(*CachedVisibilityChunk)[CurrentCell.DataOffset];
				}
				else
				{
					const FCompressedVisibilityChunk& CompressedChunk = Handler.PrecomputedVisibilityCellBuckets[PrecomputedVisibilityBucketIndex].CellDataChunks[CurrentCell.ChunkIndex];
					CachedVisibilityBucketIndex = PrecomputedVisibilityBucketIndex;
					CachedVisibilityChunkIndex = CurrentCell.ChunkIndex;
					CachedVisibilityHandlerId = Scene->PrecomputedVisibilityHandler->GetId();

					if (CompressedChunk.bCompressed)
					{
						// Decompress the needed visibility data chunk
						DecompressedVisibilityChunk.Reset();
						DecompressedVisibilityChunk.AddUninitialized(CompressedChunk.UncompressedSize);
						verify(FCompression::UncompressMemory(
							COMPRESS_ZLIB, 
							DecompressedVisibilityChunk.GetData(),
							CompressedChunk.UncompressedSize,
							CompressedChunk.Data.GetData(),
							CompressedChunk.Data.Num()));
						CachedVisibilityChunk = &DecompressedVisibilityChunk;
					}
					else
					{
						CachedVisibilityChunk = &CompressedChunk.Data;
					}

					checkSlow(CachedVisibilityChunk->Num() >= CurrentCell.DataOffset + CurrentBucket.CellDataSize);
					// Return a pointer to the cell containing ViewOrigin's decompressed visibility data
					PrecomputedVisibilityData = &(*CachedVisibilityChunk)[CurrentCell.DataOffset];
				}

				if (GShowRelevantPrecomputedVisibilityCells)
				{
					// Draw the currently used visibility cell with green wireframe for debugging
					DrawWireBox(&VisibilityCellsPDI, CellBounds, FColor(50, 255, 50), SDPG_Foreground);
				}
				else
				{
					break;
				}
			}
			else if (GShowRelevantPrecomputedVisibilityCells)
			{
				// Draw all cells in the current visibility bucket as blue wireframe
				DrawWireBox(&VisibilityCellsPDI, CellBounds, FColor(50, 50, 255), SDPG_World);
			}
		}
	}
	return PrecomputedVisibilityData;
}
void FDebugRenderSceneProxy::GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const 
{
	QUICK_SCOPE_CYCLE_COUNTER( STAT_DebugRenderSceneProxy_GetDynamicMeshElements );

	// Draw solid spheres
	struct FMaterialCache
	{
		FMaterialCache() : bUseFakeLight(false) {}

		FMaterialRenderProxy* operator[](FLinearColor Color)
		{
			FMaterialRenderProxy* MeshColor = NULL;
			const uint32 HashKey = GetTypeHash(Color);
			if (MeshColorInstances.Contains(HashKey))
			{
				MeshColor = *MeshColorInstances.Find(HashKey);
			}
			else
			{
				if (bUseFakeLight && SolidMeshMaterial.IsValid())
				{
					
					MeshColor = new(FMemStack::Get())  FColoredMaterialRenderProxy(
						SolidMeshMaterial->GetRenderProxy(false, false),
						Color,
						"GizmoColor"
						);
				}
				else
				{
					MeshColor = new(FMemStack::Get()) FColoredMaterialRenderProxy(GEngine->DebugMeshMaterial->GetRenderProxy(false, false), Color);
				}

				MeshColorInstances.Add(HashKey, MeshColor);
			}

			return MeshColor;
		}

		void UseFakeLight(bool UseLight, class UMaterial* InMaterial) { bUseFakeLight = UseLight; SolidMeshMaterial = InMaterial; }

		TMap<uint32, FMaterialRenderProxy*> MeshColorInstances;
		TWeakObjectPtr<class UMaterial> SolidMeshMaterial;
		bool bUseFakeLight;
	};

	FMaterialCache MaterialCache[2];
	MaterialCache[1].UseFakeLight(true, SolidMeshMaterial.Get());

	for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
	{
		if (VisibilityMap & (1 << ViewIndex))
		{
			const FSceneView* View = Views[ViewIndex];
			FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex);

			// Draw Lines
			const int32 LinesNum = Lines.Num();
			PDI->AddReserveLines(SDPG_World, LinesNum, false, false);
			for (const auto& CurrentLine : Lines)
			{
				PDI->DrawLine(CurrentLine.Start, CurrentLine.End, CurrentLine.Color, SDPG_World, CurrentLine.Thickness, 0, CurrentLine.Thickness > 0);
			}

			// Draw Dashed Lines
			for(int32 DashIdx=0; DashIdx<DashedLines.Num(); DashIdx++)
			{
				const FDashedLine& Dash = DashedLines[DashIdx];

				DrawDashedLine(PDI, Dash.Start, Dash.End, Dash.Color, Dash.DashSize, SDPG_World);
			}

			// Draw Arrows
			const uint32 ArrowsNum = ArrowLines.Num();
			PDI->AddReserveLines(SDPG_World, 5 * ArrowsNum, false, false);
			for (const auto& CurrentArrow : ArrowLines)
			{
				DrawLineArrow(PDI, CurrentArrow.Start, CurrentArrow.End, CurrentArrow.Color, 8.0f);
			}

			// Draw Stars
			for(int32 StarIdx=0; StarIdx<Stars.Num(); StarIdx++)
			{
				const FWireStar& Star = Stars[StarIdx];

				DrawWireStar(PDI, Star.Position, Star.Size, Star.Color, SDPG_World);
			}

			// Draw Cylinders
			for(const auto& Cylinder : Cylinders)
			{
				if (DrawType == SolidAndWireMeshes || DrawType == WireMesh)
				{
					DrawWireCylinder(PDI, Cylinder.Base, FVector(1, 0, 0), FVector(0, 1, 0), FVector(0, 0, 1), Cylinder.Color, Cylinder.Radius, Cylinder.HalfHeight, (DrawType == SolidAndWireMeshes) ? 9 : 16, SDPG_World, DrawType == SolidAndWireMeshes ? 2 : 0, 0, true);
				}

				if (DrawType == SolidAndWireMeshes || DrawType == SolidMesh)
				{
					GetCylinderMesh(Cylinder.Base, FVector(1, 0, 0), FVector(0, 1, 0), FVector(0, 0, 1), Cylinder.Radius, Cylinder.HalfHeight, 16, MaterialCache[0][Cylinder.Color.WithAlpha(DrawAlpha)], SDPG_World, ViewIndex, Collector);
				}
			}

			// Draw Boxes
			for(const auto& Box :  Boxes)
			{
				if (DrawType == SolidAndWireMeshes || DrawType == WireMesh)
				{
					DrawWireBox(PDI, Box.Transform.ToMatrixWithScale(), Box.Box, Box.Color, SDPG_World, DrawType == SolidAndWireMeshes ? 2 : 0, 0, true);
				}
				if (DrawType == SolidAndWireMeshes || DrawType == SolidMesh)
				{
					GetBoxMesh(FTransform(Box.Box.GetCenter()).ToMatrixNoScale() * Box.Transform.ToMatrixWithScale(), Box.Box.GetExtent(), MaterialCache[0][Box.Color.WithAlpha(DrawAlpha)], SDPG_World, ViewIndex, Collector);
				}
			}

			// Draw Boxes
			TArray<FVector> Verts;
			for (auto& CurrentCone : Cones)
			{
				if (DrawType == SolidAndWireMeshes || DrawType == WireMesh)
				{
					DrawWireCone(PDI, Verts, CurrentCone.ConeToWorld, 1, CurrentCone.Angle2, (DrawType == SolidAndWireMeshes) ? 9 : 16, CurrentCone.Color, SDPG_World, DrawType == SolidAndWireMeshes ? 2 : 0, 0, true);
				}
				if (DrawType == SolidAndWireMeshes || DrawType == SolidMesh)
				{
					GetConeMesh(CurrentCone.ConeToWorld, CurrentCone.Angle1, CurrentCone.Angle2, 16, MaterialCache[0][CurrentCone.Color.WithAlpha(DrawAlpha)], SDPG_World, ViewIndex, Collector);
				}
			}

			for (auto It = Spheres.CreateConstIterator(); It; ++It)
			{
				if (PointInView(It->Location, View))
				{
					if (DrawType == SolidAndWireMeshes || DrawType == WireMesh)
					{
						DrawWireSphere(PDI, It->Location, It->Color.WithAlpha(255), It->Radius, 20, SDPG_World, DrawType == SolidAndWireMeshes ? 2 : 0, 0, true);
					}
					if (DrawType == SolidAndWireMeshes || DrawType == SolidMesh)
					{
						GetSphereMesh(It->Location, FVector(It->Radius), 20, 7, MaterialCache[0][It->Color.WithAlpha(DrawAlpha)], SDPG_World, false, ViewIndex, Collector);
					}
				}
			}

			for (auto It = Capsles.CreateConstIterator(); It; ++It)
			{
				if (PointInView(It->Location, View))
				{
					if (DrawType == SolidAndWireMeshes || DrawType == WireMesh)
					{
						const float HalfAxis = FMath::Max<float>(It->HalfHeight - It->Radius, 1.f);
						const FVector BottomEnd = It->Location + It->Radius * It->Z;
						const FVector TopEnd = BottomEnd + (2 * HalfAxis) * It->Z;
						const float CylinderHalfHeight = (TopEnd - BottomEnd).Size() * 0.5;
						const FVector CylinderLocation = BottomEnd + CylinderHalfHeight * It->Z;
						DrawWireCapsule(PDI, CylinderLocation, It->X, It->Y, It->Z, It->Color, It->Radius, It->HalfHeight, (DrawType == SolidAndWireMeshes) ? 9 : 16, SDPG_World, DrawType == SolidAndWireMeshes ? 2 : 0, 0, true);
					}
					if (DrawType == SolidAndWireMeshes || DrawType == SolidMesh)
					{
						GetCapsuleMesh(It->Location, It->X, It->Y, It->Z, It->Color, It->Radius, It->HalfHeight, 16, MaterialCache[0][It->Color.WithAlpha(DrawAlpha)], SDPG_World, false, ViewIndex, Collector);
					}
				}
			}

			for (const auto& Mesh : Meshes)
			{
				FDynamicMeshBuilder MeshBuilder;
				MeshBuilder.AddVertices(Mesh.Vertices);
				MeshBuilder.AddTriangles(Mesh.Indices);

				MeshBuilder.GetMesh(FMatrix::Identity, MaterialCache[Mesh.Color.A == 255 ? 1 : 0][Mesh.Color.WithAlpha(DrawAlpha)], SDPG_World, false, false, ViewIndex, Collector);
			}

		}
	}
}