// Copyright Epic Games, Inc. All Rights Reserved. #include "Field/FieldSystemNodes.h" #include "Field/FieldSystemNoiseAlgo.h" #include "Async/ParallelFor.h" #include "Chaos/Vector.h" #include namespace { inline FVector MinVector(const FVector& VectorA, const FVector& VectorB) { return FVector(FMath::Min(VectorA.X, VectorB.X), FMath::Min(VectorA.Y, VectorB.Y), FMath::Min(VectorA.Z, VectorB.Z)); } inline FVector MaxVector(const FVector& VectorA, const FVector& VectorB) { return FVector(FMath::Max(VectorA.X, VectorB.X), FMath::Max(VectorA.Y, VectorB.Y), FMath::Max(VectorA.Z, VectorB.Z)); } } FFieldNodeBase * FieldNodeFactory(FFieldNodeBase::EFieldType BaseType,FFieldNodeBase::ESerializationType Type) { switch (Type) { case FFieldNodeBase::ESerializationType::FieldNode_FUniformInteger: return new FUniformInteger(); case FFieldNodeBase::ESerializationType::FieldNode_FRadialIntMask: return new FRadialIntMask(); case FFieldNodeBase::ESerializationType::FieldNode_FUniformScalar: return new FUniformScalar(); case FFieldNodeBase::ESerializationType::FieldNode_FWaveScalar: return new FWaveScalar(); case FFieldNodeBase::ESerializationType::FieldNode_FRadialFalloff: return new FRadialFalloff(); case FFieldNodeBase::ESerializationType::FieldNode_FPlaneFalloff: return new FPlaneFalloff(); case FFieldNodeBase::ESerializationType::FieldNode_FBoxFalloff: return new FBoxFalloff(); case FFieldNodeBase::ESerializationType::FieldNode_FNoiseField: return new FNoiseField(); case FFieldNodeBase::ESerializationType::FieldNode_FUniformVector: return new FUniformVector(); case FFieldNodeBase::ESerializationType::FieldNode_FRadialVector: return new FRadialVector(); case FFieldNodeBase::ESerializationType::FieldNode_FRandomVector: return new FRandomVector(); case FFieldNodeBase::ESerializationType::FieldNode_FSumScalar: return new FSumScalar(); case FFieldNodeBase::ESerializationType::FieldNode_FSumVector: return new FSumVector(); case FFieldNodeBase::ESerializationType::FieldNode_FConversionField: if(BaseType==FFieldNodeBase::EFieldType::EField_Int32) return new FConversionField(); else if (BaseType == FFieldNodeBase::EFieldType::EField_Float) return new FConversionField(); break; case FFieldNodeBase::ESerializationType::FieldNode_FCullingField: if (BaseType == FFieldNodeBase::EFieldType::EField_Int32) return new FCullingField(); if (BaseType == FFieldNodeBase::EFieldType::EField_Float) return new FCullingField(); if (BaseType == FFieldNodeBase::EFieldType::EField_FVector) return new FCullingField(); break; case FFieldNodeBase::ESerializationType::FieldNode_FReturnResultsTerminal: if(BaseType==FFieldNodeBase::EFieldType::EField_Int32) return new FReturnResultsTerminal(); else if (BaseType == FFieldNodeBase::EFieldType::EField_Float) return new FReturnResultsTerminal(); else if (BaseType == FFieldNodeBase::EFieldType::EField_FVector) return new FReturnResultsTerminal(); break; } return nullptr; } template void SerializeInternal(FArchive& Ar, TUniquePtr< FFieldNode >& Field) { uint8 dType = Field.IsValid() ? (uint8)Field->Type() : (uint8)FFieldNodeBase::EFieldType::EField_None; Ar << dType; uint8 sType = Field.IsValid() ? (uint8)Field->SerializationType() : (uint8)FFieldNodeBase::ESerializationType::FieldNode_Null; Ar << sType; if (Ar.IsLoading()) { Field.Reset(static_cast* >(FieldNodeFactory((FFieldNodeBase::EFieldType)dType, (FFieldNodeBase::ESerializationType)sType))); } if (Field.IsValid()) { Field->Serialize(Ar); } } template void SerializeInternal(FArchive& Ar, Enum& Var) { uint8 Type = (uint8)Var; Ar << Type; Var = (Enum)Type; } /** * FUniformInteger */ void FUniformInteger::Evaluate(FFieldContext& Context, TFieldArrayView& Results) const { int32 MagnitudeVal = Magnitude; int32 NumSamples = Context.SampleIndices.Num(); for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { Results[Context.SampleIndices[SampleIndex].Result] = MagnitudeVal; } } void FUniformInteger::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar << Magnitude; } bool FUniformInteger::operator==(const FFieldNodeBase& Node) { if (Node.SerializationType() == SerializationType()) { return Super::operator==(Node) && Magnitude == static_cast(&Node)->Magnitude; } return false; } void FUniformInteger::FillSetupCount(int32& NumOffsets, int32& NumParams) const { Super::FillSetupCount(NumOffsets, NumParams); NumParams += 1; } void FUniformInteger::FillSetupDatas(TArray& NodesOffsets, TArray& NodesParams, const float CommandTime) const { Super::FillSetupDatas(NodesOffsets, NodesParams, CommandTime); NodesParams.Add(static_cast(Magnitude)); } float FUniformInteger::EvalMaxMagnitude() const { return static_cast(Magnitude); } /** * FRadialIntMask */ void FRadialIntMask::Evaluate(FFieldContext& Context, TFieldArrayView& Results) const { float Radius2 = Radius * Radius; int32 NumSamples = Context.SampleIndices.Num(); for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = Context.SampleIndices[SampleIndex]; { int32 Result; FVector::FReal Delta2 = (Position - Context.SamplePositions[Index.Sample]).SizeSquared(); if(Delta2 < Radius2) { Result = InteriorValue; } else { Result = ExteriorValue; } switch (SetMaskCondition) { case ESetMaskConditionType::Field_Set_Always: Results[Index.Result] = Result; break; case ESetMaskConditionType::Field_Set_IFF_NOT_Interior: if (Results[Index.Result] != InteriorValue) { Results[Index.Result] = Result; } break; case ESetMaskConditionType::Field_Set_IFF_NOT_Exterior: if (Results[Index.Result] != ExteriorValue) { Results[Index.Result] = Result; } break; } } } } void FRadialIntMask::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar << Radius; Ar << Position; Ar << InteriorValue; Ar << ExteriorValue; SerializeInternal(Ar, SetMaskCondition); } bool FRadialIntMask::operator==(const FFieldNodeBase& Node) { if (Node.SerializationType() == SerializationType()) { const FRadialIntMask* Other = static_cast(&Node); return Super::operator==(Node) && Radius == Other->Radius && Position==Other->Position && InteriorValue==Other->InteriorValue && ExteriorValue==Other->ExteriorValue && SetMaskCondition== Other->SetMaskCondition; } return false; } void FRadialIntMask::FillSetupCount(int32& NumOffsets, int32& NumParams) const { Super::FillSetupCount(NumOffsets, NumParams); NumParams += 7; } void FRadialIntMask::FillSetupDatas(TArray& NodesOffsets, TArray& NodesParams, const float CommandTime) const { Super::FillSetupDatas(NodesOffsets, NodesParams, CommandTime); NodesParams.Add(Radius); NodesParams.Add(static_cast(Position.X)); NodesParams.Add(static_cast(Position.Y)); NodesParams.Add(static_cast(Position.Z)); NodesParams.Add(static_cast(InteriorValue)); NodesParams.Add(static_cast(ExteriorValue)); NodesParams.Add(static_cast(SetMaskCondition)); } float FRadialIntMask::EvalMaxMagnitude() const { return 1.0f; } void FRadialIntMask::ComputeFieldBounds(FVector& MinBounds, FVector& MaxBounds, FVector& CenterPosition) const { MinBounds = (ExteriorValue == 0) ? Position - FVector(Radius) : FVector(-FLT_MAX); MaxBounds = (ExteriorValue == 0) ? Position + FVector(Radius) : FVector(FLT_MAX); CenterPosition = Position; } /** * FUniformScalar */ void FUniformScalar::Evaluate(FFieldContext& Context, TFieldArrayView& Results) const { float MagnitudeVal = Magnitude; int32 NumSamples = Context.SampleIndices.Num(); for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { Results[Context.SampleIndices[SampleIndex].Result] = MagnitudeVal; } } void FUniformScalar::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar << Magnitude; } bool FUniformScalar::operator==(const FFieldNodeBase& Node) { if (Node.SerializationType() == SerializationType()) { return Super::operator==(Node) && Magnitude == static_cast(&Node)->Magnitude; } return false; } void FUniformScalar::FillSetupCount(int32& NumOffsets, int32& NumParams) const { Super::FillSetupCount(NumOffsets, NumParams); NumParams += 1; } void FUniformScalar::FillSetupDatas(TArray& NodesOffsets, TArray& NodesParams, const float CommandTime) const { Super::FillSetupDatas(NodesOffsets, NodesParams, CommandTime); NodesParams.Add(Magnitude); } float FUniformScalar::EvalMaxMagnitude() const { return Magnitude; } /** * FWaveScalar */ void FWaveScalar::Evaluate(FFieldContext& Context, TFieldArrayView& Results) const { const float Velocity = (Period != 0.0f ) ? Wavelength / Period : 0.0f; const float Wavenumber = (Wavelength != 0.0f ) ? 2.0f * UE_PI / Wavelength : 0.0f; const Chaos::FReal DeltaTime = FMath::Max(Context.TimeSeconds, 0.0f); const Chaos::FReal Radius = Wavelength * DeltaTime / Period; const Chaos::FReal Decay = DeltaTime / Period; int32 NumSamples = Context.SampleIndices.Num(); for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = Context.SampleIndices[SampleIndex]; if (Function == EWaveFunctionType::Field_Wave_Decay) { Results[Index.Result] = Magnitude * (float)FMath::Exp(-Decay * Decay); // LWC_TODO: Precision loss } else { const Chaos::FReal Distance = (float)(Context.SamplePositions[Index.Sample] - Position).Size(); const Chaos::FReal Fraction = (1.0f - Distance / Radius); const Chaos::FReal Phase = -Wavenumber * Radius * Fraction; if (Function == EWaveFunctionType::Field_Wave_Cosine) { Results[Index.Result] = Magnitude * (float)FMath::Cos(Phase); // LWC_TODO: Precision loss } else if (Function == EWaveFunctionType::Field_Wave_Gaussian) { Results[Index.Result] = Magnitude * (float)FMath::Exp(-Phase * Phase); // LWC_TODO: Precision loss } else if (Function == EWaveFunctionType::Field_Wave_Falloff) { if (Distance < Radius && Radius > 0) { if (Falloff == EFieldFalloffType::Field_FallOff_None) { Results[Index.Result] = Magnitude; } else if (Falloff == EFieldFalloffType::Field_Falloff_Linear) { Results[Index.Result] = Magnitude * float(Fraction); // LWC_TODO: Precision loss } else if (Falloff == EFieldFalloffType::Field_Falloff_Squared) { Results[Index.Result] = Magnitude * float(Fraction * Fraction); // LWC_TODO: Precision loss } else if (Falloff == EFieldFalloffType::Field_Falloff_Inverse && Fraction > 0.0f) { Results[Index.Result] = Magnitude * 2.0f * (1.0f - 1.0f / float(Fraction + 1.0f)); // LWC_TODO: Precision loss } else if (Falloff == EFieldFalloffType::Field_Falloff_Logarithmic) { Results[Index.Result] = Magnitude * FMath::LogX(2.0f, (float)Fraction + 1.0f); // LWC_TODO: Precision loss } } else { Results[Index.Result] = 0.0f; } } } } } void FWaveScalar::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar << Magnitude; Ar << Position; Ar << Wavelength; Ar << Period; SerializeInternal(Ar, Function); SerializeInternal(Ar, Falloff); } bool FWaveScalar::operator==(const FFieldNodeBase& Node) { if (Node.SerializationType() == SerializationType()) { return Super::operator==(Node) && Magnitude == static_cast(&Node)->Magnitude && Position == static_cast(&Node)->Position && Wavelength == static_cast(&Node)->Wavelength && Period == static_cast(&Node)->Period && Function == static_cast(&Node)->Function && Falloff == static_cast(&Node)->Falloff; } return false; } void FWaveScalar::FillSetupCount(int32& NumOffsets, int32& NumParams) const { Super::FillSetupCount(NumOffsets, NumParams); NumParams += 9; } void FWaveScalar::FillSetupDatas(TArray& NodesOffsets, TArray& NodesParams,const float CommandTime) const { Super::FillSetupDatas(NodesOffsets, NodesParams, CommandTime); NodesParams.Add(Magnitude); NodesParams.Add(static_cast(Position.X)); NodesParams.Add(static_cast(Position.Y)); NodesParams.Add(static_cast(Position.Z)); NodesParams.Add(Wavelength); NodesParams.Add(Period); NodesParams.Add(CommandTime); NodesParams.Add(static_cast(Function)); NodesParams.Add(static_cast(Falloff)); } float FWaveScalar::EvalMaxMagnitude() const { return Magnitude; } void FWaveScalar::ComputeFieldBounds(FVector& MinBounds, FVector& MaxBounds, FVector& CenterPosition) const { MinBounds = FVector(-FLT_MAX); MaxBounds = FVector(FLT_MAX); CenterPosition = Position; } /** * Function Utils */ float ScaleFunctionResult(const float& MinRange, const float& DeltaRange, const float& NodeMagnitude, const float& FunctionResult) { return NodeMagnitude * (MinRange + DeltaRange * FunctionResult); } template float EvalFalloffFunction(const float& MinRange, const float& DeltaRange, const float& NodeMagnitude, const float& FalloffValue) { return 0.0; } template<> float EvalFalloffFunction(const float& MinRange, const float& DeltaRange, const float& NodeMagnitude, const float& FalloffValue) { return ScaleFunctionResult(MinRange, DeltaRange, NodeMagnitude, 1.0); } template<> float EvalFalloffFunction(const float& MinRange, const float& DeltaRange, const float& NodeMagnitude, const float& FalloffValue) { return ScaleFunctionResult(MinRange, DeltaRange, NodeMagnitude, FalloffValue); } template<> float EvalFalloffFunction(const float& MinRange, const float& DeltaRange, const float& NodeMagnitude, const float& FalloffValue) { return ScaleFunctionResult(MinRange, DeltaRange, NodeMagnitude, FalloffValue * FalloffValue); } template<> float EvalFalloffFunction(const float& MinRange, const float& DeltaRange, const float& NodeMagnitude, const float& FalloffValue) { return ScaleFunctionResult(MinRange, DeltaRange, NodeMagnitude, 2.0f * (1.0f - 1.0f / (FalloffValue + 1.0f))); } template<> float EvalFalloffFunction(const float& MinRange, const float& DeltaRange, const float& NodeMagnitude, const float& FalloffValue) { return ScaleFunctionResult(MinRange, DeltaRange, NodeMagnitude, FMath::LogX(2.0f, FalloffValue + 1.0f)); } /** * FRadialFalloff */ template void FRadialFalloff::Evaluator(const FFieldContext& Context, TFieldArrayView& Results) const { if (Radius > 0.f) { const float DeltaRange = (MaxRange - MinRange); const int32 NumSamples = Context.SampleIndices.Num(); for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = Context.SampleIndices[SampleIndex]; { Results[Index.Result] = Default; const FVector::FReal Delta = (Context.SamplePositions[Index.Sample] - Position).Size(); if (Delta < Radius) { const float Function = float(1.0f - Delta / Radius); // LWC_TODO: Precision loss Results[Index.Result] = EvalFalloffFunction(MinRange, DeltaRange, Magnitude, Function); } } } } } void FRadialFalloff::Evaluate(FFieldContext& Context, TFieldArrayView& Results) const { switch (Falloff) { case EFieldFalloffType::Field_FallOff_None: Evaluator(Context, Results); break; case EFieldFalloffType::Field_Falloff_Linear: Evaluator(Context, Results); break; case EFieldFalloffType::Field_Falloff_Squared: Evaluator(Context, Results); break; case EFieldFalloffType::Field_Falloff_Inverse: Evaluator(Context, Results); break; case EFieldFalloffType::Field_Falloff_Logarithmic: Evaluator(Context, Results); break; } } void FRadialFalloff::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar << Magnitude; Ar << MinRange; Ar << MaxRange; Ar << Default; Ar << Radius; Ar << Position; SerializeInternal(Ar, Falloff); } bool FRadialFalloff::operator==(const FFieldNodeBase& Node) { if (Node.SerializationType() == SerializationType()) { const FRadialFalloff* Other = static_cast(&Node); return Super::operator==(Node) && Magnitude == Other->Magnitude && MinRange == Other->MinRange && MaxRange == Other->MaxRange && Default == Other->Default && Radius == Other->Radius && Position == Other->Position && Falloff == Other->Falloff; } return false; } void FRadialFalloff::FillSetupCount(int32& NumOffsets, int32& NumParams) const { Super::FillSetupCount(NumOffsets, NumParams); NumParams += 9; } void FRadialFalloff::FillSetupDatas(TArray& NodesOffsets, TArray& NodesParams, const float CommandTime) const { Super::FillSetupDatas(NodesOffsets, NodesParams, CommandTime); NodesParams.Add(Magnitude); NodesParams.Add(MinRange); NodesParams.Add(MaxRange); NodesParams.Add(Default); NodesParams.Add(Radius); NodesParams.Add(static_cast(Position.X)); NodesParams.Add(static_cast(Position.Y)); NodesParams.Add(static_cast(Position.Z)); NodesParams.Add(static_cast(Falloff)); } float FRadialFalloff::EvalMaxMagnitude() const { return Magnitude; } void FRadialFalloff::ComputeFieldBounds(FVector& MinBounds, FVector& MaxBounds, FVector& CenterPosition) const { MinBounds = (Default == 0) ? Position - FVector(Radius) : FVector(-FLT_MAX); MaxBounds = (Default == 0) ? Position + FVector(Radius) : FVector(FLT_MAX); CenterPosition = Position; } /** * FPlaneFalloff */ template void FPlaneFalloff::Evaluator(const FFieldContext& Context, const FPlane& Plane, TFieldArrayView& Results) const { if (Distance > 0.f) { const float DeltaRange = (MaxRange - MinRange); const int32 NumSamples = Context.SampleIndices.Num(); for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = Context.SampleIndices[SampleIndex]; { Results[Index.Result] = Default; const FPlane::FReal Delta = Plane.PlaneDot(Context.SamplePositions[Index.Sample]); if (Delta < -UE_SMALL_NUMBER && Delta > -Distance) { const float Function = float(1.0f + Delta / Distance); // LWC_TODO: Precision loss Results[Index.Result] = EvalFalloffFunction(MinRange, DeltaRange, Magnitude, Function); } } } } } void FPlaneFalloff::Evaluate(FFieldContext& Context, TFieldArrayView& Results) const { FPlane Plane(Position, Normal); switch (Falloff) { case EFieldFalloffType::Field_FallOff_None: Evaluator(Context, Plane, Results); break; case EFieldFalloffType::Field_Falloff_Linear: Evaluator(Context, Plane, Results); break; case EFieldFalloffType::Field_Falloff_Squared: Evaluator(Context, Plane, Results); break; case EFieldFalloffType::Field_Falloff_Inverse: Evaluator(Context, Plane, Results); break; case EFieldFalloffType::Field_Falloff_Logarithmic: Evaluator(Context, Plane, Results); break; } } void FPlaneFalloff::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar << Magnitude; Ar << MinRange; Ar << MaxRange; Ar << Default; Ar << Distance; Ar << Position; Ar << Normal; SerializeInternal(Ar, Falloff); } bool FPlaneFalloff::operator==(const FFieldNodeBase& Node) { if (Node.SerializationType() == SerializationType()) { const FPlaneFalloff* Other = static_cast(&Node); return Super::operator==(Node) && Magnitude == Other->Magnitude && MinRange == Other->MinRange && MaxRange == Other->MaxRange && Default == Other->Default && Distance == Other->Distance && Position == Other->Position && Normal == Other->Normal && Falloff == Other->Falloff; } return false; } void FPlaneFalloff::FillSetupCount(int32& NumOffsets, int32& NumParams) const { Super::FillSetupCount(NumOffsets, NumParams); NumParams += 12; } void FPlaneFalloff::FillSetupDatas(TArray& NodesOffsets, TArray& NodesParams, const float CommandTime) const { Super::FillSetupDatas(NodesOffsets, NodesParams, CommandTime); NodesParams.Add(Magnitude); NodesParams.Add(MinRange); NodesParams.Add(MaxRange); NodesParams.Add(Default); NodesParams.Add(Distance); NodesParams.Add(static_cast(Position.X)); NodesParams.Add(static_cast(Position.Y)); NodesParams.Add(static_cast(Position.Z)); NodesParams.Add(static_cast(Normal.X)); NodesParams.Add(static_cast(Normal.Y)); NodesParams.Add(static_cast(Normal.Z)); NodesParams.Add(static_cast(Falloff)); } float FPlaneFalloff::EvalMaxMagnitude() const { return Magnitude; } void FPlaneFalloff::ComputeFieldBounds(FVector& MinBounds, FVector& MaxBounds, FVector& CenterPosition) const { MinBounds = FVector(-FLT_MAX); MaxBounds = FVector(FLT_MAX); CenterPosition = Position; } /** * FBoxFalloff */ template void FBoxFalloff::Evaluator(const FFieldContext& Context, TFieldArrayView& Results) const { const float DeltaRange = (MaxRange - MinRange); static const float HalfBox = 50.0; static const FBox UnitBox(FVector(-HalfBox), FVector(HalfBox)); const int32 NumSamples = Context.SampleIndices.Num(); for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = Context.SampleIndices[SampleIndex]; { Results[Index.Result] = Default; const FVector LocalPoint = Transform.InverseTransformPosition(Context.SamplePositions[Index.Sample]); if (UnitBox.IsInside(LocalPoint)) { const FVector Distance(FMath::Abs(LocalPoint.X)- HalfBox, FMath::Abs(LocalPoint.Y) - HalfBox, FMath::Abs(LocalPoint.Z) - HalfBox); const float Delta = (float)FMath::Min(FMath::Max(Distance.X, FMath::Max(Distance.Y, Distance.Z)), 0.0f); // LWC_TODO: Precision loss const float Function = - Delta / HalfBox; Results[Index.Result] = EvalFalloffFunction(MinRange, DeltaRange, Magnitude, Function); } } } } void FBoxFalloff::Evaluate(FFieldContext& Context, TFieldArrayView& Results) const { switch (Falloff) { case EFieldFalloffType::Field_FallOff_None: Evaluator(Context, Results); break; case EFieldFalloffType::Field_Falloff_Linear: Evaluator(Context, Results); break; case EFieldFalloffType::Field_Falloff_Squared: Evaluator(Context, Results); break; case EFieldFalloffType::Field_Falloff_Inverse: Evaluator(Context, Results); break; case EFieldFalloffType::Field_Falloff_Logarithmic: Evaluator(Context, Results); break; } } void FBoxFalloff::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar << Magnitude; Ar << MinRange; Ar << MaxRange; Ar << Default; Ar << Transform; SerializeInternal(Ar, Falloff); } bool FBoxFalloff::operator==(const FFieldNodeBase& Node) { if (Node.SerializationType() == SerializationType()) { const FBoxFalloff* Other = static_cast(&Node); bool bRet = Super::operator==(Node); bRet &= Magnitude == Other->Magnitude; bRet &= MinRange == Other->MinRange; bRet &= MaxRange == Other->MaxRange; bRet &= Default == Other->Default; bRet &= Transform.Equals(Other->Transform); bRet &= Falloff == Other->Falloff; return bRet; } return false; } void FBoxFalloff::FillSetupCount(int32& NumOffsets, int32& NumParams) const { Super::FillSetupCount(NumOffsets, NumParams); NumParams += 15; } void FBoxFalloff::FillSetupDatas(TArray& NodesOffsets, TArray& NodesParams, const float CommandTime) const { Super::FillSetupDatas(NodesOffsets, NodesParams, CommandTime); NodesParams.Add(Magnitude); NodesParams.Add(MinRange); NodesParams.Add(MaxRange); NodesParams.Add(Default); NodesParams.Add(static_cast(Transform.GetRotation().X)); NodesParams.Add(static_cast(Transform.GetRotation().Y)); NodesParams.Add(static_cast(Transform.GetRotation().Z)); NodesParams.Add(static_cast(Transform.GetRotation().W)); NodesParams.Add(static_cast(Transform.GetTranslation().X)); NodesParams.Add(static_cast(Transform.GetTranslation().Y)); NodesParams.Add(static_cast(Transform.GetTranslation().Z)); NodesParams.Add(static_cast(Transform.GetScale3D().X)); NodesParams.Add(static_cast(Transform.GetScale3D().Y)); NodesParams.Add(static_cast(Transform.GetScale3D().Z)); NodesParams.Add(static_cast(Falloff)); } float FBoxFalloff::EvalMaxMagnitude() const { return Magnitude; } void FBoxFalloff::ComputeFieldBounds(FVector& MinBounds, FVector& MaxBounds, FVector& CenterPosition) const { MinBounds = FVector(-FLT_MAX); MaxBounds = FVector(FLT_MAX); if (Default == 0) { const FBox UnitBox(FVector(-50), FVector(50)); const FBox BoundingBox = UnitBox.TransformBy(Transform); MinBounds = BoundingBox.Min; MaxBounds = BoundingBox.Max; } CenterPosition = Transform.GetTranslation(); } /** * FNoiseField */ void FNoiseField::Evaluate(FFieldContext& Context, TFieldArrayView& Results) const { const float DeltaRange = (MaxRange - MinRange); const int32 NumSamples = Context.SampleIndices.Num(); for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = Context.SampleIndices[SampleIndex]; FVector::FReal Dummy = 0.0f; FVector LocalPoint = Transform.InverseTransformPosition(Context.SamplePositions[Index.Sample]); LocalPoint = FVector(FMath::Modf(LocalPoint.X, &Dummy) * 0.5f + 0.5f, FMath::Modf(LocalPoint.Y, &Dummy) * 0.5f + 0.5f, FMath::Modf(LocalPoint.Z, &Dummy) * 0.5f + 0.5f) * 255; // Samples for the Perlin noise must be btw 0->255 float PerlinValue = 0.0f; Field::PerlinNoise::Sample(&PerlinValue, (float)LocalPoint.X, (float)LocalPoint.Y, (float)LocalPoint.Z); // Perlin noise result is btw -1 -> 1 PerlinValue = 0.5f * ( PerlinValue + 1.0f ); Results[Index.Result] = ScaleFunctionResult(MinRange, DeltaRange, 1.0f, PerlinValue); } } void FNoiseField::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar << MinRange; Ar << MaxRange; Ar << Transform; } bool FNoiseField::operator==(const FFieldNodeBase& Node) { if (Node.SerializationType() == SerializationType()) { const FNoiseField* Other = static_cast(&Node); return Super::operator==(Node) && MinRange == Other->MinRange && MaxRange == Other->MaxRange && Transform.Equals(Other->Transform); } return false; } void FNoiseField::FillSetupCount(int32& NumOffsets, int32& NumParams) const { Super::FillSetupCount(NumOffsets, NumParams); NumParams += 12; } void FNoiseField::FillSetupDatas(TArray& NodesOffsets, TArray& NodesParams, const float CommandTime) const { Super::FillSetupDatas(NodesOffsets, NodesParams, CommandTime); NodesParams.Add(MinRange); NodesParams.Add(MaxRange); NodesParams.Add(static_cast(Transform.GetRotation().X)); NodesParams.Add(static_cast(Transform.GetRotation().Y)); NodesParams.Add(static_cast(Transform.GetRotation().Z)); NodesParams.Add(static_cast(Transform.GetRotation().W)); NodesParams.Add(static_cast(Transform.GetTranslation().X)); NodesParams.Add(static_cast(Transform.GetTranslation().Y)); NodesParams.Add(static_cast(Transform.GetTranslation().Z)); NodesParams.Add(static_cast(Transform.GetScale3D().X)); NodesParams.Add(static_cast(Transform.GetScale3D().Y)); NodesParams.Add(static_cast(Transform.GetScale3D().Z)); } float FNoiseField::EvalMaxMagnitude() const { return MaxRange; } /** * FUniformVector */ void FUniformVector::Evaluate(FFieldContext& Context, TFieldArrayView& Results) const { const FVector DirectionVal = Direction; const float MagnitudeVal = Magnitude; const int32 NumSamples = Context.SampleIndices.Num(); for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { Results[Context.SampleIndices[SampleIndex].Result] = MagnitudeVal * DirectionVal; } } void FUniformVector::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar << Magnitude; Ar << Direction; } bool FUniformVector::operator==(const FFieldNodeBase& Node) { if (Node.SerializationType() == SerializationType()) { const FUniformVector* Other = static_cast(&Node); return Super::operator==(Node) && Magnitude == Other->Magnitude && Direction == Other->Direction; } return false; } void FUniformVector::FillSetupCount(int32& NumOffsets, int32& NumParams) const { Super::FillSetupCount(NumOffsets, NumParams); NumParams += 4; } void FUniformVector::FillSetupDatas(TArray& NodesOffsets, TArray& NodesParams, const float CommandTime) const { Super::FillSetupDatas(NodesOffsets, NodesParams, CommandTime); NodesParams.Add(Magnitude); NodesParams.Add(static_cast(Direction.X)); NodesParams.Add(static_cast(Direction.Y)); NodesParams.Add(static_cast(Direction.Z)); } float FUniformVector::EvalMaxMagnitude() const { return Magnitude; } /** * FRadialVector */ void FRadialVector::Evaluate(FFieldContext& Context, TFieldArrayView& Results) const { const int32 NumSamples = Context.SampleIndices.Num(); for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = Context.SampleIndices[SampleIndex]; { Results[Index.Result] = Magnitude * (Context.SamplePositions[Index.Sample] - Position).GetSafeNormal(); } } } void FRadialVector::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar << Magnitude; Ar << Position; } bool FRadialVector::operator==(const FFieldNodeBase& Node) { if (Node.SerializationType() == SerializationType()) { const FRadialVector* Other = static_cast(&Node); return Super::operator==(Node) && Magnitude == Other->Magnitude && Position == Other->Position; } return false; } void FRadialVector::FillSetupCount(int32& NumOffsets, int32& NumParams) const { Super::FillSetupCount(NumOffsets, NumParams); NumParams += 4; } void FRadialVector::FillSetupDatas(TArray& NodesOffsets, TArray& NodesParams, const float CommandTime) const { Super::FillSetupDatas(NodesOffsets, NodesParams, CommandTime); NodesParams.Add(Magnitude); NodesParams.Add(static_cast(Position.X)); NodesParams.Add(static_cast(Position.Y)); NodesParams.Add(static_cast(Position.Z)); } float FRadialVector::EvalMaxMagnitude() const { return Magnitude; } void FRadialVector::ComputeFieldBounds(FVector& MinBounds, FVector& MaxBounds, FVector& CenterPosition) const { MinBounds = FVector(-FLT_MAX); MaxBounds = FVector(FLT_MAX); CenterPosition = Position; } /** * FRandomVector */ void FRandomVector::Evaluate(FFieldContext& Context, TFieldArrayView& Results) const { const int32 NumSamples = Context.SampleIndices.Num(); for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = Context.SampleIndices[SampleIndex]; { Results[Index.Result].X = FMath::RandRange(-1.f, 1.f); Results[Index.Result].Y = FMath::RandRange(-1.f, 1.f); Results[Index.Result].Z = FMath::RandRange(-1.f, 1.f); Results[Index.Result].Normalize(); Results[Index.Result] *= Magnitude; } } } void FRandomVector::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar << Magnitude; } bool FRandomVector::operator==(const FFieldNodeBase& Node) { if (Node.SerializationType() == SerializationType()) { return Super::operator==(Node) && Magnitude == static_cast(&Node)->Magnitude; } return false; } void FRandomVector::FillSetupCount(int32& NumOffsets, int32& NumParams) const { Super::FillSetupCount(NumOffsets, NumParams); NumParams += 1; } void FRandomVector::FillSetupDatas(TArray& NodesOffsets, TArray& NodesParams, const float CommandTime) const { Super::FillSetupDatas(NodesOffsets, NodesParams, CommandTime); NodesParams.Add(Magnitude); } float FRandomVector::EvalMaxMagnitude() const { return Magnitude; } /** * FSumScalar * */ void FSumScalar::Evaluate(FFieldContext& ContextIn, TFieldArrayView& Results) const { TUniquePtr > ResultsData(new FFieldSystemMetaDataResults(Results)); FScopedFieldContextMetaData ScopedMetaData(ContextIn, ResultsData.Get()); const int32 NumResults = Results.Num(); const int32 NumSamples = ContextIn.SampleIndices.Num(); const FFieldNode * RightField = ScalarRight.Get(); const FFieldNode * LeftField = ScalarLeft.Get(); float MagnitudeVal = Magnitude; if (LeftField != nullptr && RightField != nullptr) { const uint32 BufferOffset = ContextIn.ScalarResults.Num(); ContextIn.ScalarResults.SetNum(BufferOffset + 2* NumResults, EAllowShrinking::No); TFieldArrayView Buffers[2] = { TFieldArrayView(ContextIn.ScalarResults,BufferOffset,NumResults), TFieldArrayView(ContextIn.ScalarResults,BufferOffset+NumResults,NumResults), }; TArray * > FieldNodes = { LeftField,RightField }; for (int32 i = 0; i < 2; i++) { if (ensureMsgf(FieldNodes[i]->Type() == FFieldNode::StaticType(), TEXT("Field system SumScalar expects float input arrays."))) { FieldNodes[i]->Evaluate(ContextIn, Buffers[i]); } } switch (Operation) { case EFieldOperationType::Field_Multiply: for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = ContextIn.SampleIndices[SampleIndex]; { Results[Index.Result] = Buffers[1][Index.Result] * Buffers[0][Index.Result]; } } break; case EFieldOperationType::Field_Divide: for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = ContextIn.SampleIndices[SampleIndex]; { Results[Index.Result] = Buffers[0][Index.Result] / Buffers[1][Index.Result]; } } break; case EFieldOperationType::Field_Add: for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = ContextIn.SampleIndices[SampleIndex]; { Results[Index.Result] = Buffers[1][Index.Result] + Buffers[0][Index.Result]; } } break; case EFieldOperationType::Field_Substract: for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = ContextIn.SampleIndices[SampleIndex]; { Results[Index.Result] = Buffers[0][Index.Result] - Buffers[1][Index.Result]; } } break; } ContextIn.ScalarResults.SetNum(BufferOffset, EAllowShrinking::No); } else if (LeftField != nullptr && ensureMsgf(ScalarLeft->Type() == FFieldNode::StaticType(), TEXT("Field system SumScalar expects float input arrays."))) { LeftField->Evaluate(ContextIn, Results); } else if (ScalarRight != nullptr && ensureMsgf(ScalarRight->Type() == FFieldNode::StaticType(), TEXT("Field system SumScalar expects float input arrays."))) { ScalarRight->Evaluate(ContextIn, Results); } if (MagnitudeVal != 1.0) { for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = ContextIn.SampleIndices[SampleIndex]; { Results[Index.Result] *= MagnitudeVal; } } } } void FSumScalar::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar << Magnitude; SerializeInternal(Ar, ScalarRight); SerializeInternal(Ar, ScalarLeft); SerializeInternal(Ar, Operation); } bool FSumScalar::operator==(const FFieldNodeBase& Node) { if (Node.SerializationType() == SerializationType()) { const FSumScalar* Other = static_cast(&Node); bool bRet = Super::operator==(Node); bRet &= Magnitude == Other->Magnitude; bRet &= FieldsEqual(ScalarRight,Other->ScalarRight); bRet &= FieldsEqual(ScalarLeft,Other->ScalarLeft); bRet &= Operation == Other->Operation; return bRet; } return false; } void FSumScalar::FillSetupCount(int32& NumOffsets, int32& NumParams) const { if (ScalarRight.IsValid()) { ScalarRight->FillSetupCount(NumOffsets, NumParams); } if (ScalarLeft.IsValid()) { ScalarLeft->FillSetupCount(NumOffsets, NumParams); } Super::FillSetupCount(NumOffsets, NumParams); NumParams += 4; } void FSumScalar::FillSetupDatas(TArray& NodesOffsets, TArray& NodesParams, const float CommandTime) const { if (ScalarRight.IsValid()) { ScalarRight->FillSetupDatas(NodesOffsets, NodesParams, CommandTime); } if (ScalarLeft.IsValid()) { ScalarLeft->FillSetupDatas(NodesOffsets, NodesParams, CommandTime); } Super::FillSetupDatas(NodesOffsets, NodesParams, CommandTime); NodesParams.Add(Magnitude); NodesParams.Add(static_cast(ScalarRight != nullptr)); NodesParams.Add(static_cast(ScalarLeft != nullptr)); NodesParams.Add(static_cast(Operation)); } float FSumScalar::EvalMaxMagnitude() const { float MaxMagnitudeA = 0.0, MaxMagnitudeB = 0.0, MaxMagnitude = 0.0; if (ScalarRight.IsValid()) { MaxMagnitudeA = ScalarRight->EvalMaxMagnitude(); } if (ScalarLeft.IsValid()) { MaxMagnitudeB = ScalarLeft->EvalMaxMagnitude(); } if (Operation == EFieldOperationType::Field_Multiply || Operation == EFieldOperationType::Field_Divide) { MaxMagnitude = (Operation == EFieldOperationType::Field_Multiply) ? MaxMagnitudeA * MaxMagnitudeB : (FMath::Abs(MaxMagnitudeA) > FLT_EPSILON) ? MaxMagnitudeB / MaxMagnitudeA : 0.0f; } else if (Operation == EFieldOperationType::Field_Add || Operation == EFieldOperationType::Field_Substract) { MaxMagnitude = FMath::Max(MaxMagnitudeA, MaxMagnitudeB); } return Magnitude * MaxMagnitude; } void FSumScalar::ComputeFieldBounds(FVector& MinBounds, FVector& MaxBounds, FVector& CenterPosition) const { FVector MinBoundsA(-FLT_MAX), MaxBoundsA(FLT_MAX), MinBoundsB(-FLT_MAX), MaxBoundsB(FLT_MAX); FVector CenterPositionA = FVector::Zero(), CenterPositionB = FVector::Zero(); if (ScalarRight.IsValid()) { ScalarRight->ComputeFieldBounds(MinBoundsA, MaxBoundsA, CenterPositionA); } if (ScalarLeft.IsValid()) { ScalarLeft->ComputeFieldBounds(MinBoundsB, MaxBoundsB, CenterPositionB); } CenterPosition = FVector::Zero(); int32 NumCenters = 0; if (CenterPositionA != FVector::Zero()) { CenterPosition += CenterPositionA; ++NumCenters; } if (CenterPositionB != FVector::Zero()) { CenterPosition += CenterPositionB; ++NumCenters; } CenterPosition = (NumCenters > 0) ? CenterPosition / NumCenters : FVector::Zero(); if (Operation == EFieldOperationType::Field_Multiply || Operation == EFieldOperationType::Field_Divide) { MinBounds = MaxVector(MinBoundsA, MinBoundsB); MaxBounds = MinVector(MaxBoundsA, MaxBoundsB); } else if (Operation == EFieldOperationType::Field_Add || Operation == EFieldOperationType::Field_Substract) { MinBounds = MinVector(MinBoundsA, MinBoundsB); MaxBounds = MaxVector(MaxBoundsA, MaxBoundsB); } } /** * FSumVector */ void FSumVector::Evaluate(FFieldContext& ContextIn, TFieldArrayView& Results) const { TUniquePtr> ResultsData(new FFieldSystemMetaDataResults(Results)); FScopedFieldContextMetaData ScopedMetaData(ContextIn, ResultsData.Get()); int32 NumResults = Results.Num(); int32 NumSamples = ContextIn.SampleIndices.Num(); const FFieldNode * ScalarField = Scalar.Get(); const FFieldNode * RightVectorField = VectorRight.Get(); const FFieldNode * LeftVectorField = VectorLeft.Get(); float MagnitudeVal = Magnitude; if (RightVectorField != nullptr && LeftVectorField != nullptr) { const uint32 BufferOffset = ContextIn.VectorResults.Num(); ContextIn.VectorResults.SetNum(BufferOffset + 2 * NumResults, EAllowShrinking::No); TFieldArrayView Buffers[2] = { TFieldArrayView(ContextIn.VectorResults, BufferOffset, NumResults), TFieldArrayView(ContextIn.VectorResults, BufferOffset + NumResults, NumResults), }; LeftVectorField->Evaluate(ContextIn, Buffers[0]); RightVectorField->Evaluate(ContextIn, Buffers[1]); switch (Operation) { case EFieldOperationType::Field_Multiply: for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = ContextIn.SampleIndices[SampleIndex]; { Results[Index.Result] = Buffers[1][Index.Result] * Buffers[0][Index.Result]; } } break; case EFieldOperationType::Field_Divide: for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = ContextIn.SampleIndices[SampleIndex]; { Results[Index.Result] = Buffers[0][Index.Result] / Buffers[1][Index.Result]; } } break; case EFieldOperationType::Field_Add: for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = ContextIn.SampleIndices[SampleIndex]; { Results[Index.Result] = Buffers[1][Index.Result] + Buffers[0][Index.Result]; } } break; case EFieldOperationType::Field_Substract: for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = ContextIn.SampleIndices[SampleIndex]; { Results[Index.Result] = Buffers[0][Index.Result] - Buffers[1][Index.Result]; } } break; } ContextIn.VectorResults.SetNum(BufferOffset, EAllowShrinking::No); } else if (LeftVectorField != nullptr) { LeftVectorField->Evaluate(ContextIn, Results); } else if (RightVectorField != nullptr) { RightVectorField->Evaluate(ContextIn, Results); } if (ScalarField != nullptr) { const uint32 BufferOffset = ContextIn.ScalarResults.Num(); ContextIn.ScalarResults.SetNum(BufferOffset + NumResults, EAllowShrinking::No); TFieldArrayView Buffer(ContextIn.ScalarResults, BufferOffset, NumResults); ScalarField->Evaluate(ContextIn, Buffer); for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = ContextIn.SampleIndices[SampleIndex]; { Results[Index.Result] *= Buffer[Index.Result]; } } ContextIn.ScalarResults.SetNum(BufferOffset, EAllowShrinking::No); } if (MagnitudeVal != 1.0) { for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = ContextIn.SampleIndices[SampleIndex]; { Results[Index.Result] *= MagnitudeVal; } } } } void FSumVector::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar << Magnitude; SerializeInternal(Ar, Scalar); SerializeInternal(Ar, VectorRight); SerializeInternal(Ar, VectorLeft); SerializeInternal(Ar, Operation); } bool FSumVector::operator==(const FFieldNodeBase& Node) { if (Node.SerializationType() == SerializationType()) { const FSumVector* Other = static_cast(&Node); return Super::operator==(Node) && Magnitude == Other->Magnitude && FieldsEqual(Scalar,Other->Scalar) && FieldsEqual(VectorRight, Other->VectorRight) && FieldsEqual(VectorLeft, Other->VectorLeft) && Operation == Other->Operation; } return false; } void FSumVector::FillSetupCount(int32& NumOffsets, int32& NumParams) const { if (Scalar.IsValid()) { Scalar->FillSetupCount(NumOffsets, NumParams); } if (VectorRight.IsValid()) { VectorRight->FillSetupCount(NumOffsets, NumParams); } if (VectorLeft.IsValid()) { VectorLeft->FillSetupCount(NumOffsets, NumParams); } Super::FillSetupCount(NumOffsets, NumParams); NumParams += 5; } void FSumVector::FillSetupDatas(TArray& NodesOffsets, TArray& NodesParams, const float CommandTime) const { if (Scalar.IsValid()) { Scalar->FillSetupDatas(NodesOffsets, NodesParams, CommandTime); } if (VectorRight.IsValid()) { VectorRight->FillSetupDatas(NodesOffsets, NodesParams, CommandTime); } if (VectorLeft.IsValid()) { VectorLeft->FillSetupDatas(NodesOffsets, NodesParams, CommandTime); } Super::FillSetupDatas(NodesOffsets, NodesParams, CommandTime); NodesParams.Add(Magnitude); NodesParams.Add(static_cast(Scalar != nullptr)); NodesParams.Add(static_cast(VectorRight != nullptr)); NodesParams.Add(static_cast(VectorLeft != nullptr)); NodesParams.Add(static_cast(Operation)); } float FSumVector::EvalMaxMagnitude() const { float MaxMagnitudeA = 0.0, MaxMagnitudeB = 0.0, MaxMagnitudeC = 0.0, MaxMagnitude = 0.0; if (Scalar.IsValid()) { MaxMagnitudeA = Scalar->EvalMaxMagnitude(); } if (VectorRight.IsValid()) { MaxMagnitudeB = VectorRight->EvalMaxMagnitude(); } if (VectorLeft.IsValid()) { MaxMagnitudeC = VectorLeft->EvalMaxMagnitude(); } if (Operation == EFieldOperationType::Field_Multiply || Operation == EFieldOperationType::Field_Divide) { MaxMagnitude = (Operation == EFieldOperationType::Field_Multiply) ? MaxMagnitudeA * MaxMagnitudeB : (FMath::Abs(MaxMagnitudeA) > FLT_EPSILON) ? MaxMagnitudeB / MaxMagnitudeA : 0.0f; } else if (Operation == EFieldOperationType::Field_Add || Operation == EFieldOperationType::Field_Substract) { MaxMagnitude = FMath::Max(MaxMagnitudeA, MaxMagnitudeB); } return Magnitude * MaxMagnitudeA * MaxMagnitude; } void FSumVector::ComputeFieldBounds(FVector& MinBounds, FVector& MaxBounds, FVector& CenterPosition) const { FVector MinBoundsA(-FLT_MAX), MaxBoundsA(FLT_MAX), MinBoundsB(-FLT_MAX), MaxBoundsB(FLT_MAX), MinBoundsC(-FLT_MAX), MaxBoundsC(FLT_MAX); FVector CenterPositionA = FVector::Zero(), CenterPositionB = FVector::Zero(), CenterPositionC = FVector::Zero(); if (Scalar.IsValid()) { Scalar->ComputeFieldBounds(MinBoundsC, MaxBoundsC, CenterPositionC); } if (VectorRight.IsValid()) { VectorRight->ComputeFieldBounds(MinBoundsA, MaxBoundsA, CenterPositionA); } if (VectorLeft.IsValid()) { VectorLeft->ComputeFieldBounds(MinBoundsB, MaxBoundsB, CenterPositionB); } CenterPosition = FVector::Zero(); int32 NumCenters = 0; if (CenterPositionA != FVector::Zero()) { CenterPosition += CenterPositionA; ++NumCenters; } if (CenterPositionB != FVector::Zero()) { CenterPosition += CenterPositionB; ++NumCenters; } if (CenterPositionC != FVector::Zero()) { CenterPosition += CenterPositionC; ++NumCenters; } CenterPosition = (NumCenters > 0) ? CenterPosition / NumCenters : FVector::Zero(); if (Operation == EFieldOperationType::Field_Multiply || Operation == EFieldOperationType::Field_Divide) { MinBounds = MaxVector(MinBoundsA, MinBoundsB); MaxBounds = MinVector(MaxBoundsA, MaxBoundsB); } else if (Operation == EFieldOperationType::Field_Add || Operation == EFieldOperationType::Field_Substract) { MinBounds = MinVector(MinBoundsA, MinBoundsB); MaxBounds = MaxVector(MaxBoundsA, MaxBoundsB); } MinBounds = MaxVector(MinBounds, MinBoundsC); MaxBounds = MinVector(MaxBounds, MaxBoundsC); } /** * FConversionField */ template void FConversionField::Evaluate(FFieldContext& Context, TFieldArrayView& Results) const { static_assert(std::is_arithmetic_v, "Arithmetic types required for field conversion"); static_assert(std::is_arithmetic_v, "Arithmetic types required for field conversion"); int32 NumResults = Results.Num(); int32 NumSamples = Context.SampleIndices.Num(); TArray& ResultsArray = GetResultArray(Context); const int32 BufferOffset = ResultsArray.Num(); ResultsArray.SetNum(BufferOffset + NumResults, EAllowShrinking::No); FMemory::Memzero(&ResultsArray[BufferOffset], sizeof(InT) * NumResults); TFieldArrayView BufferView(ResultsArray, BufferOffset, NumResults); InputField->Evaluate(Context, BufferView); for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = Context.SampleIndices[SampleIndex]; Results[Index.Result] = (OutT)BufferView[Index.Result]; } ResultsArray.SetNum(BufferOffset, EAllowShrinking::No); } template void FConversionField::Serialize(FArchive& Ar) { Super::Serialize(Ar); SerializeInternal(Ar, InputField); } template bool FConversionField::operator==(const FFieldNodeBase& Node) { if (Node.SerializationType() == SerializationType()) { const FConversionField* Other = static_cast*>(&Node); return Super::operator==(Node) && FieldsEqual(InputField,Other->InputField); } return false; } template void FConversionField::FillSetupCount(int32& NumOffsets, int32& NumParams) const { if (InputField.IsValid()) { InputField->FillSetupCount(NumOffsets, NumParams); } Super::FillSetupCount(NumOffsets, NumParams); NumParams += 1; } template void FConversionField::FillSetupDatas(TArray& NodesOffsets, TArray& NodesParams, const float CommandTime) const { if (InputField.IsValid()) { InputField->FillSetupDatas(NodesOffsets, NodesParams, CommandTime); } Super::FillSetupDatas(NodesOffsets, NodesParams, CommandTime); NodesParams.Add(static_cast(InputField != nullptr)); } template float FConversionField::EvalMaxMagnitude() const { float MaxMagnitude = 0.0; if (InputField.IsValid()) { MaxMagnitude = InputField->EvalMaxMagnitude(); } return MaxMagnitude; } template void FConversionField::ComputeFieldBounds(FVector& MinBounds, FVector& MaxBounds, FVector& CenterPosition) const { FVector MinBoundsA(-FLT_MAX), MaxBoundsA(FLT_MAX); if (InputField.IsValid()) { InputField->ComputeFieldBounds(MinBoundsA, MaxBoundsA, CenterPosition); } MinBounds = MinBoundsA; MaxBounds = MaxBoundsA; } template class FConversionField; template class FConversionField; /** * FCullingField */ template void FCullingField::Evaluate(FFieldContext& Context, TFieldArrayView& Results) const { int32 NumResults = Results.Num(); int32 NumSamples = Context.SampleIndices.Num(); const FFieldNode * CullingField = Culling.Get(); const FFieldNode * InputField = Input.Get(); if (CullingField != nullptr) { if (ensureMsgf(CullingField->Type() == FFieldNode::StaticType(), TEXT("Field Node CullingFields Culling input expects a float input array."))) { const uint32 BufferOffset = Context.ScalarResults.Num(); Context.ScalarResults.SetNum(BufferOffset + NumResults, EAllowShrinking::No); TFieldArrayView CullingBuffer(Context.ScalarResults, BufferOffset, NumResults); FMemory::Memzero(&Context.ScalarResults[BufferOffset], sizeof(float) * NumResults); CullingField->Evaluate(Context, CullingBuffer); const uint32 IndexOffset = Context.IndexResults.Num(); Context.IndexResults.SetNum(IndexOffset + NumResults, EAllowShrinking::No); TFieldArrayView IndexBuffer(Context.IndexResults, IndexOffset, NumResults); int NewEvaluationSize = 0; for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { const FFieldContextIndex& Index = Context.SampleIndices[SampleIndex]; { if (Operation == EFieldCullingOperationType::Field_Culling_Outside) { if (CullingBuffer[Index.Result] != 0) { IndexBuffer[NewEvaluationSize++] = Context.SampleIndices[SampleIndex]; } } else { if (CullingBuffer[Index.Result] == 0) { IndexBuffer[NewEvaluationSize++] = Context.SampleIndices[SampleIndex]; } } } } Context.ScalarResults.SetNum(BufferOffset, EAllowShrinking::No); if (NewEvaluationSize) { Context.IndexResults.SetNum(IndexOffset + NewEvaluationSize, EAllowShrinking::No); FFieldSystemMetaDataCulling* CullingData = static_cast(Context.MetaData[FFieldSystemMetaData::EMetaType::ECommandData_Culling]); if (CullingData) { CullingData->bCullingActive = true; CullingData->CullingIndices.SetNum(NewEvaluationSize, EAllowShrinking::No); FMemory::Memcpy(&CullingData->CullingIndices[0], &Context.IndexResults[IndexOffset], NewEvaluationSize * sizeof(FFieldContextIndex)); if (InputField) { TFieldArrayView LocalIndices(Context.IndexResults, IndexOffset, NewEvaluationSize); FFieldContext LocalContext(LocalIndices, Context.SamplePositions, Context.MetaData, Context.TimeSeconds, Context.VectorResults, Context.ScalarResults, Context.IntegerResults, Context.IndexResults, CullingData->CullingIndices); InputField->Evaluate(LocalContext, Results); } } } Context.IndexResults.SetNum(IndexOffset, EAllowShrinking::No); } } else if( InputField!=nullptr) { InputField->Evaluate(Context, Results); } } template void FCullingField::Serialize(FArchive& Ar) { Super::Serialize(Ar); SerializeInternal(Ar, Culling); SerializeInternal(Ar, Input); SerializeInternal(Ar, Operation); } template bool FCullingField::operator==(const FFieldNodeBase& Node) { if (Node.SerializationType() == SerializationType()) { const FCullingField* Other = static_cast*>(&Node); return Super::operator==(Node) && FieldsEqual(Culling,Other->Culling) && FieldsEqual(Input,Other->Input) && Operation == Other->Operation; } return false; } template void FCullingField::FillSetupCount(int32& NumOffsets, int32& NumParams) const { if (Culling.IsValid()) { Culling->FillSetupCount(NumOffsets, NumParams); } if (Input.IsValid()) { Input->FillSetupCount(NumOffsets, NumParams); } Super::FillSetupCount(NumOffsets, NumParams); NumParams += 3; } template void FCullingField::FillSetupDatas(TArray& NodesOffsets, TArray& NodesParams, const float CommandTime) const { if (Culling.IsValid()) { Culling->FillSetupDatas(NodesOffsets, NodesParams, CommandTime); } if (Input.IsValid()) { Input->FillSetupDatas(NodesOffsets, NodesParams, CommandTime); } Super::FillSetupDatas(NodesOffsets, NodesParams, CommandTime); NodesParams.Add(static_cast(Culling != nullptr)); NodesParams.Add(static_cast(Input != nullptr)); NodesParams.Add(static_cast(Operation)); } template float FCullingField::EvalMaxMagnitude() const { float MaxMagnitude = 0.0; if (Input.IsValid()) { MaxMagnitude = Input->EvalMaxMagnitude(); } return MaxMagnitude; } template void FCullingField::ComputeFieldBounds(FVector& MinBounds, FVector& MaxBounds, FVector& CenterPosition) const { FVector MinBoundsA(-FLT_MAX), MaxBoundsA(FLT_MAX), MinBoundsB(-FLT_MAX), MaxBoundsB(FLT_MAX); FVector CenterPositionA = FVector::Zero(), CenterPositionB = FVector::Zero(); if (Culling.IsValid()) { Culling->ComputeFieldBounds(MinBoundsA, MaxBoundsA, CenterPositionA); } if (Input.IsValid()) { Input->ComputeFieldBounds(MinBoundsB, MaxBoundsB, CenterPositionB); } CenterPosition = FVector::Zero(); int32 NumCenters = 0; if (CenterPositionA != FVector::Zero()) { CenterPosition += CenterPositionA; ++NumCenters; } if (CenterPositionB != FVector::Zero()) { CenterPosition += CenterPositionB; ++NumCenters; } CenterPosition = (NumCenters > 0) ? CenterPosition / NumCenters : FVector::Zero(); if (Operation == EFieldCullingOperationType::Field_Culling_Inside) { MinBounds = MinVector(MinBoundsA, MinBoundsB); MaxBounds = MaxVector(MaxBoundsA, MaxBoundsB); } else if (Operation == EFieldCullingOperationType::Field_Culling_Outside) { MinBounds = MaxVector(MinBoundsA, MinBoundsB); MaxBounds = MinVector(MaxBoundsA, MaxBoundsB); } } template class FCullingField; template class FCullingField; template class FCullingField; /** * FReturnResultsTerminal */ template void FReturnResultsTerminal::Evaluate(FFieldContext& Context, TFieldArrayView& Results) const { if (ensureMsgf(Context.MetaData.Contains(FFieldSystemMetaData::EMetaType::ECommandData_Results), TEXT("Return results nodes can only be used upstream from a 'results expector', for example as an input " "to a Operator Node . See documentation for details."))) { FFieldSystemMetaDataResults * ResultsMetaData = static_cast*>(Context.MetaData[FFieldSystemMetaData::EMetaType::ECommandData_Results]); ensure(ResultsMetaData->Results.Num() == Results.Num()); int32 NumSamples = Context.SampleIndices.Num(); for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++) { Results[Context.SampleIndices[SampleIndex].Result] = ResultsMetaData->Results[Context.SampleIndices[SampleIndex].Result]; } } } template void FReturnResultsTerminal::Serialize(FArchive& Ar) { Super::Serialize(Ar); } template bool FReturnResultsTerminal::operator==(const FFieldNodeBase& Node) { if (Node.SerializationType() == SerializationType()) { return true; } return false; } template class FReturnResultsTerminal; template class FReturnResultsTerminal; template class FReturnResultsTerminal;