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());
}
}