FTimerHandle timerHandle_ObjectComputeTimer; FTimerHandle timerHandle_AddObjectsTimer;
USTRUCT() struct FFadeObjStruct { GENERATED_USTRUCT_BODY() UPROPERTY() UPrimitiveComponent* primitiveComp; UPROPERTY() TArray<UMaterialInterface*> baseMatInterface; UPROPERTY() TArray<UMaterialInstanceDynamic*> fadeMID; UPROPERTY() float fadeCurrent; UPROPERTY() bool bToHide; void NewElement(UPrimitiveComponent* newComponent, TArray<UMaterialInterface*> newBaseMat, <UMaterialInstanceDynamic*> newMID, float currentFade, bool bHide) { primitiveComp = newComponent; baseMatInterface = newBaseMat; fadeMID = newMID; fadeCurrent = currentFade; bToHide = bHide; } void SetHideOnly(bool hide) { bToHide = hide; } void SetFadeAndHide(float newFade, bool newHide) { fadeCurrent = newFade; bToHide = newHide; } //For Destroy void Destroy() { primitiveComp = nullptr; } //Constructor FFadeObjStruct() { primitiveComp = nullptr; fadeCurrent = 0; bToHide = true; } };
// Check trace block by this UPROPERTY(EditAnywhere, Category = "Fade Objects") TArray<TEnumAsByte<ECollisionChannel>> objectTypes; // Trace object size UPROPERTY(EditAnywhere, Category = "Fade Objects") float capsuleHalfHeight; // Trace object size UPROPERTY(EditAnywhere, Category = "Fade Objects") float capsuleRadius;
UPROPERTY(EditAnywhere, Category = "Fade Objects") float workDistance;
UPROPERTY(EditAnywhere, Category = "Fade Objects") UClass* playerClass;
GetWorld()->GetTimerManager().SetTimer(timerHandle_AddObjectsTimer, this, &USFadeObjectsComponent::AddObjectsToHide, addObjectInterval, true); GetWorld()->GetTimerManager().SetTimer(timerHandle_ObjectComputeTimer, this, &USFadeObjectsComponent::FadeObjWorker, calcFadeInterval, true);
void USFadeObjectsComponent::AddObjectsToHide() { UGameplayStatics::GetAllActorsOfClass(this, playerClass, characterArray); for (AActor* currentActor : characterArray) { const FVector traceStart = GEngine->GetFirstLocalPlayerController(GetWorld())->PlayerCameraManager->GetCameraLocation(); const FVector traceEnd = currentActor->GetActorLocation(); const FRotator traceRot = currentActor->GetActorRotation(); FVector traceLentgh = traceStart - traceEnd; const FQuat acQuat = currentActor->GetActorQuat(); if (traceLentgh.Size() < workDistance) { FCollisionQueryParams traceParams(TEXT("FadeObjectsTrace"), true, GetOwner()); traceParams.AddIgnoredActors(actorsIgnore); traceParams.bTraceAsyncScene = true; traceParams.bReturnPhysicalMaterial = false; // Not tracing complex uses the rough collision instead making tiny objects easier to select. traceParams.bTraceComplex = false; TArray<FHitResult> hitArray; TArray<TEnumAsByte<EObjectTypeQuery>> traceObjectTypes; // Convert ECollisionChannel to ObjectType for (int i = 0; i < objectTypes.Num(); ++i) { traceObjectTypes.Add(UEngineTypes::ConvertToObjectType(objectTypes[i].GetValue())); } // Check distance between camera and player for new object to fade, and add this in array GetWorld()->SweepMultiByObjectType(hitArray, traceStart, traceEnd, acQuat, traceObjectTypes, FCollisionShape::MakeCapsule(capsuleRadius, capsuleHalfHeight), traceParams); for (int hA = 0; hA < hitArray.Num(); ++hA) { if (hitArray[hA].bBlockingHit && IsValid(hitArray[hA].GetComponent()) && !fadeObjectsHit.Contains(hitArray[hA].GetComponent())) { fadeObjectsHit.AddUnique(hitArray[hA].GetComponent()); } } } } // Make fade array after complete GetAllActorsOfClass loop for (int fO = 0; fO < fadeObjectsHit.Num(); ++fO) { // If not contains this component in fadeObjectsTemp if (!fadeObjectsTemp.Contains(fadeObjectsHit[fO])) { TArray<UMaterialInterface*> lBaseMaterials; TArray<UMaterialInstanceDynamic*> lMidMaterials; lBaseMaterials.Empty(); lMidMaterials.Empty(); fadeObjectsTemp.AddUnique(fadeObjectsHit[fO]); // For loop all materials ID in object for (int nM = 0; nM < fadeObjectsHit[fO]->GetNumMaterials(); ++nM) { lMidMaterials.Add(UMaterialInstanceDynamic::Create(fadeMaterial, fadeObjectsHit[fO])); lBaseMaterials.Add(fadeObjectsHit[fO]->GetMaterial(nM)); // Set new material on object fadeObjectsHit[fO]->SetMaterial(nM, lMidMaterials.Last()); } // Create new fade object in array of objects to fade FFadeObjStruct newObject; newObject.NewElement(fadeObjectsHit[fO], lBaseMaterials, lMidMaterials, immediatelyFade, true); // Add object to array fadeObjects.Add(newObject); // Set collision on Primitive Component fadeObjectsHit[fO]->SetCollisionResponseToChannel(ECC_Camera, ECR_Ignore); } } // Set hide to visible true if contains for (int fOT = 0; fOT < fadeObjectsTemp.Num(); ++fOT) { if (!fadeObjectsHit.Contains(fadeObjectsTemp[fOT])) { fadeObjects[fOT].SetHideOnly(false); } } // Clear array fadeObjectsHit.Empty(); }
void USFadeObjectsComponent::FadeObjWorker() { if (fadeObjects.Num() > 0) { // For loop all fade objects for (int i = 0; i < fadeObjects.Num(); ++i) { // Index of iteration int fnID = i; float adaptiveFade; if (fnID == fadeObjects.Num()) { adaptiveFade = nearObjectFade; } else { adaptiveFade = farObjectFade; } // For loop fadeMID array for (int t = 0; t < fadeObjects[i].fadeMID.Num(); ++t) { float targetF; const float currentF = fadeObjects[i].fadeCurrent; if (fadeObjects[i].bToHide) { targetF = adaptiveFade; } else { targetF = 1.0f; } const float newFade = FMath::FInterpConstantTo(currentF, targetF, GetWorld()->GetDeltaSeconds(), fadeRate); fadeObjects[i].fadeMID[t]->SetScalarParameterValue("Fade", newFade); currentFade = newFade; fadeObjects[i].SetFadeAndHide(newFade, fadeObjects[i].bToHide); } // remove index in array if (currentFade == 1.0f) { for (int bmi = 0; bmi < fadeObjects[fnID].baseMatInterface.Num(); ++bmi) { fadeObjects[fnID].primitiveComp->SetMaterial(bmi, fadeObjects[fnID].baseMatInterface[bmi]); } fadeObjects[fnID].primitiveComp->SetCollisionResponseToChannel(ECC_Camera, ECR_Block); fadeObjects.RemoveAt(fnID); fadeObjectsTemp.RemoveAt(fnID); } } } }
PrimaryComponentTick.bCanEverTick = false; bEnable = true; addObjectInterval = 0.1f; calcFadeInterval = 0.05f; fadeRate = 10.0f; capsuleHalfHeight = 88.0f; capsuleRadius = 34.0f; workDistance = 5000.0f; nearCameraRadius = 300.0f; nearObjectFade = 0.3; farObjectFade = 0.1; immediatelyFade = 0.5f; // Add first collision type objectTypes.Add(ECC_WorldStatic);
Source: https://habr.com/ru/post/425389/
All Articles