void ASpawnWithHoudini::RandomizeActor()

in Ambit/Source/Ambit/Actors/Spawners/SpawnWithHoudini.cpp [194:313]


void ASpawnWithHoudini::RandomizeActor(UHoudiniPublicAPIAssetWrapper* SpawnedActor)
{
    if (SpawnedActor->IsValidLowLevel())
    {
        int32 AssetIndexInList = INDEX_NONE;
        const int32 ListNumber = HoudiniAssetDetails.IndexOfByPredicate(
            [SpawnedActor, &AssetIndexInList](const FHoudiniLoadableAsset& asset)
            {
                AssetIndexInList = asset.SpawnedActors.IndexOfByKey(SpawnedActor);
                return AssetIndexInList != INDEX_NONE;
            });

        TMap<FName, FHoudiniParameterTuple> ActorExistingParameterMap;
        TMap<FName, FHoudiniParameterTuple> ActorNewParameterMap;

        // Since this task is parallelized, we need to ensure that this seed is the same per actor,
        // but different enough from all other actors.
        if (ListNumber != INDEX_NONE)
        {
            int32 AssetSeed = 100 * RandomSeed + 10 * ListNumber + AssetIndexInList;
            Random.Initialize(AssetSeed);
        }

        const bool bActiveParameters = SpawnedActor->GetParameterTuples(ActorExistingParameterMap);
        if (bActiveParameters)
        {
            for (const auto& ParameterTuple : ActorExistingParameterMap)
            {
                FHoudiniParameterTuple NewParameterValue;

                const FName ParameterName = ParameterTuple.Key;
                FHoudiniParameterTuple CurrentTuples = ParameterTuple.Value;

                // If the ParamsToRandom does not have the parameter, we skip it and take whatever it has.
                if (ListNumber != INDEX_NONE && HoudiniAssetDetails[ListNumber].ParamsToRandom.Contains(ParameterName))
                {
                    for (int i = 0; i < CurrentTuples.BoolValues.Num(); i++)
                    {
                        bool bRandomBool = Random.RandRange(0, 1) == 1;
                        NewParameterValue.BoolValues.Add(bRandomBool);
                    }

                    for (int i = 0; i < CurrentTuples.FloatValues.Num(); i++)
                    {
                        float RandomFloat = Random.FRandRange(0, FloatMax);
                        NewParameterValue.FloatValues.Add(RandomFloat);
                    }

                    for (int i = 0; i < CurrentTuples.Int32Values.Num(); i++)
                    {
                        int RandomInt = Random.RandRange(0, IntMax);
                        NewParameterValue.Int32Values.Add(RandomInt);
                    }

                    // Currently, we shouldn't randomize strings. Keep them the same values to keep param list happy.
                    for (int i = 0; i < CurrentTuples.StringValues.Num(); i++)
                    {
                        FString PreviousString = CurrentTuples.StringValues[i];
                        NewParameterValue.StringValues.Add(PreviousString);
                    }

                    for (int i = 0; i < CurrentTuples.FloatRampPoints.Num(); i++)
                    {
                        // For the sake of simplicity, this keeps the numbers sane.
                        const float InPosition = CurrentTuples.FloatRampPoints[i].Position;
                        const float InValue = Random.FRandRange(0, FloatMax);
                        const EHoudiniPublicAPIRampInterpolationType InterpolationType = static_cast<
                            EHoudiniPublicAPIRampInterpolationType>(Random.RandRange(1, 7));

                        FHoudiniPublicAPIFloatRampPoint RandomFloatRamp = FHoudiniPublicAPIFloatRampPoint(
                            InPosition, InValue, InterpolationType);
                        NewParameterValue.FloatRampPoints.Add(RandomFloatRamp);
                    }

                    for (int i = 0; i < CurrentTuples.ColorRampPoints.Num(); i++)
                    {
                        // Seeded variant of FLinearColor::MakeRandomColor
                        const uint8 Hue = static_cast<uint8>(Random.RandRange(0, 255));
                        const uint8 Saturation = static_cast<uint8>(Random.RandRange(0, 255));
                        const uint8 Brightness = static_cast<uint8>(Random.RandRange(0, 255));
                        const FLinearColor Color = FLinearColor::MakeFromHSV8(Hue, Saturation, Brightness);

                        // For the sake of simplicity, this keeps the numbers sane.
                        const float InPosition = CurrentTuples.ColorRampPoints[i].Position;
                        const EHoudiniPublicAPIRampInterpolationType InterpolationType = static_cast<
                            EHoudiniPublicAPIRampInterpolationType>(Random.RandRange(1, 7));

                        FHoudiniPublicAPIColorRampPoint RandomColorRamp = FHoudiniPublicAPIColorRampPoint(
                            InPosition, Color, InterpolationType);
                        NewParameterValue.ColorRampPoints.Add(RandomColorRamp);
                    }

                    ActorNewParameterMap.Add(ParameterName, NewParameterValue);
                }
                else
                {
                    ActorNewParameterMap.Add(ParameterName, CurrentTuples);
                }
            }

            const bool bResolved = SpawnedActor->SetParameterTuples(ActorNewParameterMap);
            if (bResolved)
            {
                SpawnedActor->Recook();
                ActorExistingParameterMap.Empty();
            }
            else
            {
                UE_LOG(LogAmbit, Warning,
                       TEXT("Houdini Asset could not be fully cooked for spawner %s and object %s. Invalid option set."
                       ), *this->GetActorLabel(), *SpawnedActor->GetName());
            }
        }
    }
    else
    {
        UE_LOG(LogAmbit, Warning, TEXT("Houdini Asset is no longer available in %s. Skipping."),
               *this->GetActorLabel());
    }
}