void DrawDebugCylinder(const UWorld* InWorld, FVector const& Start, FVector const& End, float Radius, int32 Segments, FColor const& Color, bool bPersistentLines, float LifeTime, uint8 DepthPriority) { // no debug line drawing on dedicated server if (GEngine->GetNetMode(InWorld) != NM_DedicatedServer) { // Need at least 4 segments Segments = FMath::Max(Segments, 4); // Rotate a point around axis to form cylinder segments FVector Segment; FVector P1, P2, P3, P4; const int32 AngleInc = 360.f / Segments; int32 Angle = AngleInc; // Default for Axis is up FVector Axis = (End - Start).SafeNormal(); if( Axis.IsZero() ) { Axis = FVector(0.f, 0.f, 1.f); } FVector Perpendicular; FVector Dummy; Axis.FindBestAxisVectors(Perpendicular, Dummy); Segment = Perpendicular.RotateAngleAxis(0, Axis) * Radius; P1 = Segment + Start; P3 = Segment + End; // this means foreground lines can't be persistent ULineBatchComponent* const LineBatcher = GetDebugLineBatcher( InWorld, bPersistentLines, LifeTime, (DepthPriority == SDPG_Foreground) ); if(LineBatcher != NULL) { while( Segments-- ) { Segment = Perpendicular.RotateAngleAxis(Angle, Axis) * Radius; P2 = Segment + Start; P4 = Segment + End; LineBatcher->DrawLine(P2, P4, Color, DepthPriority); LineBatcher->DrawLine(P1, P2, Color, DepthPriority); LineBatcher->DrawLine(P3, P4, Color, DepthPriority); P1 = P2; P3 = P4; Angle += AngleInc; } } } }
void UEnvQueryGenerator_OnCircle::GenerateItems(FEnvQueryInstance& QueryInstance) const { float AngleDegree = 360.f; float RadiusValue = 0.f; float ItemSpace = 1.0f; if (QueryInstance.GetParamValue(Angle, AngleDegree, TEXT("Angle")) == false || QueryInstance.GetParamValue(Radius, RadiusValue, TEXT("Radius")) == false || QueryInstance.GetParamValue(ItemSpacing, ItemSpace, TEXT("ItemSpacing")) == false || AngleDegree <= 0.f || AngleDegree > 360.f || RadiusValue <= 0.f) { return; } AngleRadians = FMath::DegreesToRadians(Angle.Value); // first generate points on a circle const float CircumferenceLength = 2.f * PI * RadiusValue; const float ArcAnglePercentage = Angle.Value / 360.f; const float ArcLength = CircumferenceLength * ArcAnglePercentage; const int32 StepsCount = FMath::CeilToInt(ArcLength / ItemSpace) + 1; const float AngleStep = AngleDegree / (StepsCount - 1); FVector StartDirection = CalcDirection(QueryInstance); TArray<FVector> CenterLocationCandidates; QueryInstance.PrepareContext(CircleCenter, CenterLocationCandidates); StartDirection = StartDirection.RotateAngleAxis(-AngleDegree/2, FVector::UpVector) * RadiusValue; int NumCenterLocations = CenterLocationCandidates.Num(); if (NumCenterLocations > 0) { for (int i = 0; i < NumCenterLocations; ++i) { GenerateItemsForCircle(CenterLocationCandidates[i], StartDirection, StepsCount, AngleStep, QueryInstance); } } else { FVector CenterLocation(0); AActor* Querier = Cast<AActor>(QueryInstance.Owner.Get()); if (Querier) { CenterLocation = Querier->GetActorLocation(); } GenerateItemsForCircle(CenterLocation, StartDirection, StepsCount, AngleStep, QueryInstance); } }
void UEnvQueryGenerator_OnCircle::GenerateItems(FEnvQueryInstance& QueryInstance) const { CircleRadius.BindData(QueryInstance.Owner.Get(), QueryInstance.QueryID); SpaceBetween.BindData(QueryInstance.Owner.Get(), QueryInstance.QueryID); ArcAngle.BindData(QueryInstance.Owner.Get(), QueryInstance.QueryID); float AngleDegree = ArcAngle.GetValue(); float RadiusValue = CircleRadius.GetValue(); float ItemSpace = SpaceBetween.GetValue(); if ((AngleDegree <= 0.f) || (AngleDegree > 360.f) || (RadiusValue <= 0.f) || (ItemSpace <= 0.f)) { return; } AngleRadians = FMath::DegreesToRadians(AngleDegree); // first generate points on a circle const float CircumferenceLength = 2.f * PI * RadiusValue; const float ArcAnglePercentage = AngleDegree / 360.f; const float ArcLength = CircumferenceLength * ArcAnglePercentage; const int32 StepsCount = FMath::CeilToInt(ArcLength / ItemSpace) + 1; const float AngleStep = AngleDegree / (StepsCount - 1); FVector StartDirection = CalcDirection(QueryInstance); StartDirection = StartDirection.RotateAngleAxis(-AngleDegree/2, FVector::UpVector) * RadiusValue; // gather context with raw data, so it can be used by derived generators FEnvQueryContextData ContextData; const bool bSuccess = QueryInstance.PrepareContext(CircleCenter, ContextData); if (bSuccess && ContextData.ValueType && ContextData.ValueType->IsChildOf(UEnvQueryItemType_VectorBase::StaticClass())) { UEnvQueryItemType_VectorBase* DefTypeOb = (UEnvQueryItemType_VectorBase*)ContextData.ValueType->GetDefaultObject(); const uint16 DefTypeValueSize = DefTypeOb->GetValueSize(); uint8* RawData = ContextData.RawData.GetData(); for (int32 ValueIndex = 0; ValueIndex < ContextData.NumValues; ValueIndex++) { const FVector ContextItemLocation = DefTypeOb->GetItemLocation(RawData); GenerateItemsForCircle(RawData, DefTypeOb, ContextItemLocation, StartDirection, StepsCount, AngleStep, QueryInstance); RawData += DefTypeValueSize; } } }
void UEnvQueryGenerator_OnCircle::GenerateItemsForCircle(uint8* ContextRawData, UEnvQueryItemType* ContextItemType, const FVector& CenterLocation, const FVector& StartDirection, int32 StepsCount, float AngleStep, FEnvQueryInstance& OutQueryInstance) const { TArray<FNavLocation> ItemCandidates; ItemCandidates.AddZeroed(StepsCount); for (int32 Step = 0; Step < StepsCount; ++Step) { ItemCandidates[Step] = FNavLocation(CenterLocation + StartDirection.RotateAngleAxis(AngleStep*Step, FVector::UpVector)); } switch (TraceData.TraceMode) { case EEnvQueryTrace::Navigation: { ANavigationData* NavData = const_cast<ANavigationData*>(FEQSHelpers::FindNavigationDataForQuery(OutQueryInstance)); if (NavData) { FEQSHelpers::RunNavRaycasts(*NavData, TraceData, CenterLocation, ItemCandidates); } } break; case EEnvQueryTrace::Geometry: FEQSHelpers::RunPhysRaycasts(OutQueryInstance.World, TraceData, CenterLocation, ItemCandidates); break; case EEnvQueryTrace::None: // Just accept the ItemCandidates as they already are (points on a circle), without using navigation OR collision. break; default: UE_VLOG(Cast<AActor>(OutQueryInstance.Owner.Get()), LogEQS, Warning, TEXT("UEnvQueryGenerator_OnCircle::CalcDirection has invalid value for TraceData.TraceMode. Query: %s"), *OutQueryInstance.QueryName); break; } ProjectAndFilterNavPoints(ItemCandidates, OutQueryInstance); AddItemDataForCircle(ContextRawData, ContextItemType, ItemCandidates, OutQueryInstance); }
FVector UKismetMathLibrary::RotateAngleAxis(FVector InVect, float AngleDeg, FVector Axis) { return InVect.RotateAngleAxis(AngleDeg, Axis.SafeNormal()); }
FVector ABxtAsteroidSpawner::GetRandomSpawnDirection() const { const FVector direction(-1.0f, 0.0, 0.0f); const float angle = FMath::FRandRange(-45.0f, 45.0f); return direction.RotateAngleAxis(angle, FVector(0.0f, 0.0f, 1.0f)); }
void UEnvQueryGenerator_OnCircle::GenerateItemsForCircle(const FVector& CenterLocation, const FVector& StartDirection, int32 StepsCount, float AngleStep, FEnvQueryInstance& OutQueryInstance) const { TArray<FVector> ItemCandidates; ItemCandidates.AddZeroed(StepsCount); for (int32 Step = 0; Step < StepsCount; ++Step) { ItemCandidates[Step] = CenterLocation + StartDirection.RotateAngleAxis(AngleStep*Step, FVector::UpVector); } #if WITH_RECAST // @todo this needs to be optimize to batch raycasts const ARecastNavMesh* NavMesh = (TraceData.TraceMode == EEnvQueryTrace::Navigation) || (ProjectionData.TraceMode == EEnvQueryTrace::Navigation) ? FEQSHelpers::FindNavMeshForQuery(OutQueryInstance) : NULL; if (NavMesh) { NavMesh->BeginBatchQuery(); } #endif if (TraceData.TraceMode == EEnvQueryTrace::Navigation) { #if WITH_RECAST if (NavMesh != NULL) { TSharedPtr<const FNavigationQueryFilter> NavigationFilter = UNavigationQueryFilter::GetQueryFilter(NavMesh, TraceData.NavigationFilter); TArray<FNavigationRaycastWork> RaycastWorkload; RaycastWorkload.Reserve(ItemCandidates.Num()); for (const auto& ItemLocation : ItemCandidates) { RaycastWorkload.Add(FNavigationRaycastWork(CenterLocation, ItemLocation)); } NavMesh->BatchRaycast(RaycastWorkload, NavigationFilter); for (int32 ItemIndex = 0; ItemIndex < ItemCandidates.Num(); ++ItemIndex) { ItemCandidates[ItemIndex] = RaycastWorkload[ItemIndex].HitLocation.Location; } } #endif } else { ECollisionChannel TraceCollisionChannel = UEngineTypes::ConvertToCollisionChannel(TraceData.TraceChannel); FVector TraceExtent(TraceData.ExtentX, TraceData.ExtentY, TraceData.ExtentZ); FCollisionQueryParams TraceParams(TEXT("EnvQueryTrace"), TraceData.bTraceComplex); TraceParams.bTraceAsyncScene = true; FBatchTracingHelper TracingHelper(OutQueryInstance.World, TraceCollisionChannel, TraceParams, TraceExtent); switch (TraceData.TraceShape) { case EEnvTraceShape::Line: TracingHelper.DoSingleSourceMultiDestinations<EEnvTraceShape::Line>(CenterLocation, ItemCandidates); break; case EEnvTraceShape::Sphere: TracingHelper.DoSingleSourceMultiDestinations<EEnvTraceShape::Sphere>(CenterLocation, ItemCandidates); break; case EEnvTraceShape::Capsule: TracingHelper.DoSingleSourceMultiDestinations<EEnvTraceShape::Capsule>(CenterLocation, ItemCandidates); break; case EEnvTraceShape::Box: TracingHelper.DoSingleSourceMultiDestinations<EEnvTraceShape::Box>(CenterLocation, ItemCandidates); break; default: UE_VLOG(Cast<AActor>(OutQueryInstance.Owner.Get()), LogEQS, Warning, TEXT("UEnvQueryGenerator_OnCircle::CalcDirection failed to calc direction in %s. Using querier facing."), *OutQueryInstance.QueryName); break; } } #if WITH_RECAST if (NavMesh) { ProjectAndFilterNavPoints(ItemCandidates, NavMesh); NavMesh->FinishBatchQuery(); } #endif for (int32 Step = 0; Step < ItemCandidates.Num(); ++Step) { OutQueryInstance.AddItemData<UEnvQueryItemType_Point>(ItemCandidates[Step]); } }
FNiagaraDynamicDataBase *NiagaraEffectRendererRibbon::GenerateVertexData(const FNiagaraEmitterParticleData &Data) { SCOPE_CYCLE_COUNTER(STAT_NiagaraGenRibbonVertexData); SimpleTimer VertexDataTimer; FNiagaraDynamicDataRibbon *DynamicData = new FNiagaraDynamicDataRibbon; TArray<FParticleBeamTrailVertex>& RenderData = DynamicData->VertexData; RenderData.Reset(Data.GetNumParticles() * 2); //CachedBounds.Init(); // build a sorted list by age, so we always get particles in order // regardless of them being moved around due to dieing and spawning TArray<int32> SortedIndices; for (uint32 Idx = 0; Idx < Data.GetNumParticles(); Idx++) { SortedIndices.Add(Idx); } const FVector4 *AgeData = Data.GetAttributeData("Age"); SortedIndices.Sort( [&AgeData](const int32& A, const int32& B) { return AgeData[A].X < AgeData[B].X; } ); FVector2D UVs[4] = { FVector2D(0.0f, 0.0f), FVector2D(1.0f, 0.0f), FVector2D(1.0f, 1.0f), FVector2D(0.0f, 1.0f) }; const FVector4 *PosPtr = Data.GetAttributeData("Position"); const FVector4 *ColorPtr = Data.GetAttributeData("Color"); const FVector4 *AgePtr = Data.GetAttributeData("Age"); const FVector4 *RotPtr = Data.GetAttributeData("Rotation"); FVector PrevPos, PrevPos2, PrevDir(0.0f, 0.0f, 0.1f); for (int32 i = 0; i < SortedIndices.Num() - 1; i++) { uint32 Index1 = SortedIndices[i]; uint32 Index2 = SortedIndices[i + 1]; const FVector ParticlePos = PosPtr[Index1]; FVector ParticleDir = PosPtr[Index2] - ParticlePos; if (ParticleDir.Size() <= SMALL_NUMBER) { ParticleDir = PrevDir*0.1f; } FVector NormDir = ParticleDir.GetSafeNormal(); FVector ParticleRight = FVector::CrossProduct(NormDir, FVector(0.0f, 0.0f, 1.0f)); ParticleRight *= RotPtr[Index1].Y; FVector ParticleRightRot = ParticleRight.RotateAngleAxis(RotPtr[Index1].X, NormDir); if (i == 0) { AddRibbonVert(RenderData, ParticlePos + ParticleRightRot, Data, UVs[0], ColorPtr[Index1], AgePtr[Index1], RotPtr[i]); AddRibbonVert(RenderData, ParticlePos - ParticleRightRot, Data, UVs[1], ColorPtr[Index1], AgePtr[Index1], RotPtr[i]); } else { AddRibbonVert(RenderData, PrevPos2, Data, UVs[0], ColorPtr[Index1], AgePtr[Index1], RotPtr[i]); AddRibbonVert(RenderData, PrevPos, Data, UVs[1], ColorPtr[Index1], AgePtr[Index1], RotPtr[i]); } ParticleRightRot = ParticleRight.RotateAngleAxis(RotPtr[Index2].X, NormDir); AddRibbonVert(RenderData, ParticlePos - ParticleRightRot + ParticleDir, Data, UVs[2], ColorPtr[Index2], AgePtr[Index2], RotPtr[i]); AddRibbonVert(RenderData, ParticlePos + ParticleRightRot + ParticleDir, Data, UVs[3], ColorPtr[Index2], AgePtr[Index2], RotPtr[i]); PrevPos = ParticlePos - ParticleRightRot + ParticleDir; PrevPos2 = ParticlePos + ParticleRightRot + ParticleDir; PrevDir = ParticleDir; } CPUTimeMS = VertexDataTimer.GetElapsedMilliseconds(); return DynamicData; }