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 ); } } }
void DrawWireBox(NxShape* box, const NxVec3& color, float lineWidth) { NxBox obb; box->isBox()->getWorldOBB(obb); DrawWireBox(obb, color, lineWidth); }
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; } }
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 }
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 ); } } }
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 ); } }
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; } } }
/** * 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); } } } }