121 TArray<UStaticMeshComponent*> MeshComponents;
122 GetComponents<UStaticMeshComponent>(MeshComponents);
127 UMaterialInstanceDynamic* Material =
nullptr;
129 int32 ModuleIndex = 0;
131 bool bClassified =
false;
133 bool bStatelessGlyph =
false;
137 for (UStaticMeshComponent* MeshComp : MeshComponents)
139 if (!MeshComp || !MeshComp->GetStaticMesh())
147 const TArray<FName> SlotNames = MeshComp->GetMaterialSlotNames();
148 for (int32 Slot = 0; Slot < SlotNames.Num(); ++Slot)
150 if (!SlotNames[Slot].ToString().StartsWith(TEXT(
"led_")))
154 const int32 MatIdx = MeshComp->GetMaterialIndex(SlotNames[Slot]);
155 if (MatIdx == INDEX_NONE)
159 UMaterialInterface* Material = MeshComp->GetMaterial(MatIdx);
164 UMaterialInstanceDynamic* DynMaterial = Cast<UMaterialInstanceDynamic>(Material);
167 DynMaterial = UMaterialInstanceDynamic::Create(Material, MeshComp);
172 MeshComp->SetMaterial(MatIdx, DynMaterial);
176 Lamp.Material = DynMaterial;
177 Lamp.SlotIndex = Slot;
178 if (!SplitHeadAndModule(MeshComp->GetName(), Lamp.HeadKey, Lamp.ModuleIndex))
180 Lamp.HeadKey = MeshComp->GetName();
181 Lamp.ModuleIndex = 0;
184 FLinearColor EmissiveColor;
185 if (DynMaterial->GetVectorParameterValue(FName(
"Emissive Color"), EmissiveColor))
187 Lamp.bClassified = ClassifyLampByColor(EmissiveColor, Lamp.State);
188 if (!Lamp.bClassified)
192 Lamp.bStatelessGlyph = EmissiveColor.R > 0.9f && EmissiveColor.G > 0.9f && EmissiveColor.B > 0.9f;
204 ETrafficLightState::Green, ETrafficLightState::Yellow, ETrafficLightState::Red};
205 int32 NumFallback = 0;
206 TMap<FString, TArray<int32>> ByHead;
207 for (int32 i = 0; i < Lamps.Num(); ++i)
209 ByHead.FindOrAdd(Lamps[i].HeadKey).Add(i);
211 for (
auto& HeadPair : ByHead)
213 TArray<int32>& Indices = HeadPair.Value;
214 if (Indices.ContainsByPredicate([&](int32 i) { return Lamps[i].bClassified || Lamps[i].bStatelessGlyph; }))
218 if (Indices.Num() != 3)
222 Indices.Sort([&](int32 A, int32 B)
224 return Lamps[A].ModuleIndex != Lamps[B].ModuleIndex
225 ? Lamps[A].ModuleIndex < Lamps[B].ModuleIndex
226 : Lamps[A].SlotIndex < Lamps[B].SlotIndex;
228 for (int32 k = 0; k < 3; ++k)
230 Lamps[Indices[k]].bClassified =
true;
231 Lamps[Indices[k]].State = ThreeAspect[k];
236 int32 NumRed = 0, NumYellow = 0, NumGreen = 0, NumStateless = 0, NumUnknown = 0;
237 for (
const FLamp& Lamp : Lamps)
239 if (!Lamp.bClassified)
242 (Lamp.bStatelessGlyph ? NumStateless : NumUnknown)++;
248 case ETrafficLightState::Red: ++NumRed;
break;
249 case ETrafficLightState::Yellow: ++NumYellow;
break;
250 default: ++NumGreen;
break;
258 Dark->SetScalarParameterValue(FName(
"Emissive Intensity"), 0.0f);
261 UE_LOG(LogCarla, Log,
262 TEXT(
"DigitalTwinsTrafficLight '%s' lamp census: %d mesh components, %d lamp slots -> "
263 "%d red, %d yellow, %d green, %d stateless, %d unclassified (%d by module order)"),
265 NumRed, NumYellow, NumGreen, NumStateless, NumUnknown, NumFallback);
267 if (Lamps.Num() == 0)
269 UE_LOG(LogCarla, Warning,
270 TEXT(
"DigitalTwinsTrafficLight '%s': no 'led_*' material slot on any of its %d mesh "
271 "components; the rig will not animate"),