# Cascade raycast

**URL:** <https://forums.unrealengine.com/t/cascade-raycast/2453531>\
**Category:** C++\
**Tags:** Raycast, unreal-engine, CPP\
**Created:** [April 12, 2025, 9:13pm UTC](https://forums.unrealengine.com/t/cascade-raycast/2453531 "2025-04-12T21:13:40Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![pyramidal](https://d3kjluh73b9h9o.cloudfront.net/original/4X/2/8/5/28502927f1d97ba1051b3b47ccfe17233bf41ef0.png) [@pyramidal](https://forums.unrealengine.com/u/pyramidal)\
**Post date:** [April 12, 2025, 9:13pm UTC](https://forums.unrealengine.com/t/cascade-raycast/2453531/1 "2025-04-12T21:13:40Z")

</div>

Hi,

I would like to code a cascading raycast like this:  
Source point = position of the emitting object  
I choose 4 directions (I could have chosen a different number)  
Four raycasts are generated from this source point to strike a first object at 4 impact points, each of which in turn becomes a source of four raycasts to strike a second object, etc.  
So I coded a C++ class called RayEmitter2, whose .h:

```auto
//RayEmitter2.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "RayEmitter2.generated.h"

UCLASS()
class ESSAI_API ARayEmitter2 : public AActor
{
	GENERATED_BODY()

public:
	ARayEmitter2();

protected:
	virtual void BeginPlay() override;

public:
	virtual void Tick(float DeltaTime) override;

	UPROPERTY(EditAnywhere, Category = "Ray Emission")
	AActor* EmitterActor;

	UPROPERTY(EditAnywhere, Category = "Ray Emission")
	TArray<FVector> EmissionDirections;

	UPROPERTY(EditAnywhere, Category = "Ray Emission")
	float RayLength = 1000.0f;

	UPROPERTY(EditAnywhere, Category = "Ray Emission")
	int32 MaxGenerations = 3;

	UPROPERTY(EditAnywhere, Category = "Ray Emission")
	FLinearColor LineColor = FLinearColor::Yellow;

	UPROPERTY(EditAnywhere, Category = "Ray Emission")
	float LineThickness = 1.0f;

	UPROPERTY(EditAnywhere, Category = "Ray Emission")
	float RayDisplayDuration = 1.0f; // Ajout de la durée d'affichage

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
	int32 nb_appel = 0;

	// Liste des points d’impact pour chaque génération
	TArray<TArray<FVector>> ImpactGenerations;

protected:
	
	// Gère les rayons pour un seul point source
	TArray<FVector> GenerateRaysFromSinglePoint(const FVector& Source);
};

```

and whose cpp is:

```auto
//RayEmitter2.cpp

#include "RayEmitter2.h"
#include "DrawDebugHelpers.h"
#include "Engine/World.h"

//2 problèmes:
//les points d'impact de la 2nd génération sont les mêmes
//le 2nd objet touché est le même que lEr objet touché

// Constructeur
ARayEmitter2::ARayEmitter2()
{
	PrimaryActorTick.bCanEverTick = true;
}

// BeginPlay
void ARayEmitter2::BeginPlay()
{
	Super::BeginPlay();

	if (!EmitterActor)
	{
		UE_LOG(LogTemp, Warning, TEXT("EmitterActor non défini"));
		return;
	}

	ImpactGenerations.Empty();

	// Génération 0 = EmitterActor (point de départ)
	TArray<FVector> CurrentSources;
	CurrentSources.Add(EmitterActor->GetActorLocation());
	ImpactGenerations.Add(CurrentSources);

	UE_LOG(LogTemp, Warning, TEXT("Démarrage des générations de rayons. MaxGenerations: %d"), MaxGenerations); // Ajout de ce log
	UE_LOG(LogTemp, Warning, TEXT("Résumé des impacts par génération :"));
	for (int32 Gen = 0; Gen < MaxGenerations; ++Gen)
	{
		UE_LOG(LogTemp, Warning, TEXT("Génération %d, Nombre de sources: %d"), Gen, CurrentSources.Num()); // Ajout de ce log

		TArray<FVector> NewImpactsThisGeneration;
		TArray<FVector> NextGenerationSources; // Pour stocker les points d'impact de cette génération
		NewImpactsThisGeneration.Empty();
		NextGenerationSources.Empty();
		for (const FVector& Source : CurrentSources)
		{
			// Émettre des rayons depuis la source actuelle
			TArray<FVector> ImpactsFromSource = GenerateRaysFromSinglePoint(Source);
			NewImpactsThisGeneration.Append(ImpactsFromSource);
			NextGenerationSources.Append(ImpactsFromSource); // Préparer les sources pour la prochaine génération
			/*
			// 🔹 Log des points sources (CurrentSources)
			FString SourcesStr;
			for (const FVector& Src : CurrentSources)
			{
				SourcesStr += FString::Printf(TEXT("%s, "), *Src.ToString());
			}
			UE_LOG(LogTemp, Warning, TEXT("Génération %d - Points source: %s"), Gen, *SourcesStr);

			// 🔹 Log des impacts trouvés
			FString ImpactsStr;
			for (const FVector& Impact : ImpactsFromSource)
			{
				ImpactsStr += FString::Printf(TEXT("%s, "), *Impact.ToString());
			}
			UE_LOG(LogTemp, Warning, TEXT("Génération %d - Points d'impact: %s"), Gen, *ImpactsStr);*/
		}

		if (NewImpactsThisGeneration.Num() == 0)
		{
			UE_LOG(LogTemp, Warning, TEXT("Génération %d: Aucun nouvel impact trouvé. Arrêt."), Gen); // Ajout de ce log
			break;
		}

		ImpactGenerations.Add(NewImpactsThisGeneration);
		CurrentSources = NextGenerationSources; // Les nouveaux impacts deviennent les sources pour la prochaine génération

		UE_LOG(LogTemp, Warning, TEXT("Génération %d: %d nouveaux impacts trouvés."), Gen, NewImpactsThisGeneration.Num()); // Ajout de ce log
	}

	UE_LOG(LogTemp, Warning, TEXT("Fin des générations de rayons.")); // Ajout de ce log
}

// Tick
void ARayEmitter2::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

TArray<FVector> ARayEmitter2::GenerateRaysFromSinglePoint(const FVector& Source)
{
	nb_appel++;
	TArray<FVector> ImpactPoints;
	ImpactPoints.Empty();

	UE_LOG(LogTemp, Warning, TEXT("GenerateRaysFromSinglePoint %d fois appelé depuis: %s"),nb_appel, *Source.ToString()); // Ajout de ce log

	for (const FVector& Direction : EmissionDirections)
	{
		UE_LOG(LogTemp, Warning, TEXT(" Direction: %s"), *Direction.ToString()); // Ajout de ce log
		FVector DirNormalized = Direction.GetSafeNormal();
		FVector End = Source + DirNormalized * RayLength;

		FHitResult Hit;
		FCollisionQueryParams Params;
		Params.AddIgnoredActor(this);
		if (EmitterActor)
			Params.AddIgnoredActor(EmitterActor);

		bool bHit = GetWorld()->LineTraceSingleByChannel(
			Hit,
			Source,
			End,
			ECollisionChannel::ECC_Visibility,
			Params
		);

		if (bHit)
		{
			UE_LOG(LogTemp, Warning, TEXT(" Normale: %s"), *Hit.ImpactNormal.ToString());

			ImpactPoints.Add(Hit.ImpactPoint);//avant
			// Décale légèrement le point d'impact dans la direction de la normale pour éviter de toucher la même surface
			//FVector AdjustedImpactPoint = Hit.ImpactPoint + Hit.ImpactNormal * 1.0f;
		   //ImpactPoints.Add(AdjustedImpactPoint);

			UE_LOG(LogTemp, Warning, TEXT(" Impact à: %s"), *Hit.ImpactPoint.ToString()); // Ajout de ce log
			/*UE_LOG(LogTemp, Warning, TEXT(" Touche: %s à %s"),
				*Hit.GetActor()->GetName(),
				*Hit.ImpactPoint.ToString());*///avant
			UE_LOG(LogTemp, Warning, TEXT(" Touche: %s (ptr: %p) à %s"),
				*Hit.GetActor()->GetName(),
				Hit.GetActor(),
				*Hit.ImpactPoint.ToString());
			// Debug visual
			//le 3ème paramètre de DrawDebugLine est un point(pas une direction)
			//DrawDebugLine(GetWorld(), Source, AdjustedImpactPoint, LineColor.ToFColor(true), false, RayDisplayDuration, 0, LineThickness);
			//DrawDebugPoint(GetWorld(), AdjustedImpactPoint, 8.0f, FColor::Red, false, RayDisplayDuration);
			DrawDebugLine(GetWorld(), Source, Hit.ImpactPoint, LineColor.ToFColor(true), false, RayDisplayDuration, 0, LineThickness);//avant
			DrawDebugPoint(GetWorld(), Hit.ImpactPoint, 8.0f, FColor::Red, false, RayDisplayDuration);//avant
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT(" Pas d'impact. Fin du rayon: %s"), *End.ToString()); // Ajout de ce log
			DrawDebugLine(GetWorld(), Source, End, FColor::Red, false, 1.0f, 0, LineThickness);
		}
	}

	UE_LOG(LogTemp, Warning, TEXT("GenerateRaysFromSinglePoint terminé. %d impacts trouvés."), ImpactPoints.Num()); // Ajout de ce log
	return ImpactPoints;
}

```

Here’s what the output log gives me:  
LogTemp: Warning: Démarrage des générations de rayons. MaxGenerations: 2  
LogTemp: Warning: Résumé des impacts par génération :  
LogTemp: Warning: Génération 0, Nombre de sources: 1  
LogTemp: Warning: GenerateRaysFromSinglePoint 1 fois appelé depuis: X=1881.093 Y=2823.205 Z=75.063  
LogTemp: Warning: Direction: X=1.000 Y=1.000 Z=1.000  
LogTemp: Warning: Normale: X=0.000 Y=0.000 Z=-1.000  
LogTemp: Warning: Impact à: X=2075.531 Y=3017.643 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=2075.531 Y=3017.643 Z=269.500  
LogTemp: Warning: Direction: X=1.000 Y=-1.000 Z=1.000  
LogTemp: Warning: Normale: X=0.000 Y=0.000 Z=-1.000  
LogTemp: Warning: Impact à: X=2075.531 Y=2628.768 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=2075.531 Y=2628.768 Z=269.500  
LogTemp: Warning: Direction: X=-1.000 Y=1.000 Z=1.000  
LogTemp: Warning: Normale: X=0.000 Y=0.000 Z=-1.000  
LogTemp: Warning: Impact à: X=1686.656 Y=3017.643 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=1686.656 Y=3017.643 Z=269.500  
LogTemp: Warning: Direction: X=-1.000 Y=-1.000 Z=1.000  
LogTemp: Warning: Normale: X=0.000 Y=0.000 Z=-1.000  
LogTemp: Warning: Impact à: X=1686.656 Y=2628.768 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=1686.656 Y=2628.768 Z=269.500  
LogTemp: Warning: GenerateRaysFromSinglePoint terminé. 4 impacts trouvés.  
LogTemp: Warning: Génération 0: 4 nouveaux impacts trouvés.  
LogTemp: Warning: Génération 1, Nombre de sources: 4  
LogTemp: Warning: GenerateRaysFromSinglePoint 2 fois appelé depuis: X=2075.531 Y=3017.643 Z=269.500  
LogTemp: Warning: Direction: X=1.000 Y=1.000 Z=1.000  
LogTemp: Warning: Normale: X=-0.577 Y=-0.577 Z=-0.577  
LogTemp: Warning: Impact à: X=2075.531 Y=3017.643 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=2075.531 Y=3017.643 Z=269.500  
LogTemp: Warning: Direction: X=1.000 Y=-1.000 Z=1.000  
LogTemp: Warning: Normale: X=-0.577 Y=0.577 Z=-0.577  
LogTemp: Warning: Impact à: X=2075.531 Y=3017.643 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=2075.531 Y=3017.643 Z=269.500  
LogTemp: Warning: Direction: X=-1.000 Y=1.000 Z=1.000  
LogTemp: Warning: Normale: X=0.577 Y=-0.577 Z=-0.577  
LogTemp: Warning: Impact à: X=2075.531 Y=3017.643 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=2075.531 Y=3017.643 Z=269.500  
LogTemp: Warning: Direction: X=-1.000 Y=-1.000 Z=1.000  
LogTemp: Warning: Normale: X=0.577 Y=0.577 Z=-0.577  
LogTemp: Warning: Impact à: X=2075.531 Y=3017.643 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=2075.531 Y=3017.643 Z=269.500  
LogTemp: Warning: GenerateRaysFromSinglePoint terminé. 4 impacts trouvés.  
LogTemp: Warning: GenerateRaysFromSinglePoint 3 fois appelé depuis: X=2075.531 Y=2628.768 Z=269.500  
LogTemp: Warning: Direction: X=1.000 Y=1.000 Z=1.000  
LogTemp: Warning: Normale: X=-0.577 Y=-0.577 Z=-0.577  
LogTemp: Warning: Impact à: X=2075.531 Y=2628.768 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=2075.531 Y=2628.768 Z=269.500  
LogTemp: Warning: Direction: X=1.000 Y=-1.000 Z=1.000  
LogTemp: Warning: Normale: X=-0.577 Y=0.577 Z=-0.577  
LogTemp: Warning: Impact à: X=2075.531 Y=2628.768 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=2075.531 Y=2628.768 Z=269.500  
LogTemp: Warning: Direction: X=-1.000 Y=1.000 Z=1.000  
LogTemp: Warning: Normale: X=0.577 Y=-0.577 Z=-0.577  
LogTemp: Warning: Impact à: X=2075.531 Y=2628.768 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=2075.531 Y=2628.768 Z=269.500  
LogTemp: Warning: Direction: X=-1.000 Y=-1.000 Z=1.000  
LogTemp: Warning: Normale: X=0.577 Y=0.577 Z=-0.577  
LogTemp: Warning: Impact à: X=2075.531 Y=2628.768 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=2075.531 Y=2628.768 Z=269.500  
LogTemp: Warning: GenerateRaysFromSinglePoint terminé. 4 impacts trouvés.  
LogTemp: Warning: GenerateRaysFromSinglePoint 4 fois appelé depuis: X=1686.656 Y=3017.643 Z=269.500  
LogTemp: Warning: Direction: X=1.000 Y=1.000 Z=1.000  
LogTemp: Warning: Normale: X=-0.577 Y=-0.577 Z=-0.577  
LogTemp: Warning: Impact à: X=1686.656 Y=3017.643 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=1686.656 Y=3017.643 Z=269.500  
LogTemp: Warning: Direction: X=1.000 Y=-1.000 Z=1.000  
LogTemp: Warning: Normale: X=-0.577 Y=0.577 Z=-0.577  
LogTemp: Warning: Impact à: X=1686.656 Y=3017.643 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=1686.656 Y=3017.643 Z=269.500  
LogTemp: Warning: Direction: X=-1.000 Y=1.000 Z=1.000  
LogTemp: Warning: Normale: X=0.577 Y=-0.577 Z=-0.577  
LogTemp: Warning: Impact à: X=1686.656 Y=3017.643 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=1686.656 Y=3017.643 Z=269.500  
LogTemp: Warning: Direction: X=-1.000 Y=-1.000 Z=1.000  
LogTemp: Warning: Normale: X=0.577 Y=0.577 Z=-0.577  
LogTemp: Warning: Impact à: X=1686.656 Y=3017.643 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=1686.656 Y=3017.643 Z=269.500  
LogTemp: Warning: GenerateRaysFromSinglePoint terminé. 4 impacts trouvés.  
LogTemp: Warning: GenerateRaysFromSinglePoint 5 fois appelé depuis: X=1686.656 Y=2628.768 Z=269.500  
LogTemp: Warning: Direction: X=1.000 Y=1.000 Z=1.000  
LogTemp: Warning: Normale: X=-0.577 Y=-0.577 Z=-0.577  
LogTemp: Warning: Impact à: X=1686.656 Y=2628.768 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=1686.656 Y=2628.768 Z=269.500  
LogTemp: Warning: Direction: X=1.000 Y=-1.000 Z=1.000  
LogTemp: Warning: Normale: X=-0.577 Y=0.577 Z=-0.577  
LogTemp: Warning: Impact à: X=1686.656 Y=2628.768 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=1686.656 Y=2628.768 Z=269.500  
LogTemp: Warning: Direction: X=-1.000 Y=1.000 Z=1.000  
LogTemp: Warning: Normale: X=0.577 Y=-0.577 Z=-0.577  
LogTemp: Warning: Impact à: X=1686.656 Y=2628.768 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=1686.656 Y=2628.768 Z=269.500  
LogTemp: Warning: Direction: X=-1.000 Y=-1.000 Z=1.000  
LogTemp: Warning: Normale: X=0.577 Y=0.577 Z=-0.577  
LogTemp: Warning: Impact à: X=1686.656 Y=2628.768 Z=269.500  
LogTemp: Warning: Touche: StaticMeshActor\_UAID\_0042C04F8026175D02\_1540545753 (ptr: 00000718B7BCD700) à X=1686.656 Y=2628.768 Z=269.500  
LogTemp: Warning: GenerateRaysFromSinglePoint terminé. 4 impacts trouvés.  
LogTemp: Warning: Génération 1: 16 nouveaux impacts trouvés.  
LogTemp: Warning: Fin des générations de rayons.

2 problems I can’t solve:  
The impact points of the second generation are the same  
The second object hit is the same as the first object hit

Here’s what I get:

 ![Capture d’écran 2025-04-12 à 23.22.47](https://d3kjluh73b9h9o.cloudfront.net/original/4X/5/6/9/56993cccc8d1e965a8a278892778979009746921.png)

Here’s what I should get:

 ![Capture d’écran 2025-03-27 à 18.28.39](https://d3kjluh73b9h9o.cloudfront.net/original/4X/c/5/6/c56cfd07eea0a24255816479885f9056a03e0953.png)

Can you help me?

thanks

---

<div class="post-metadata">

**Author:** ![dZh0](https://d3kjluh73b9h9o.cloudfront.net/original/4X/2/8/5/28502927f1d97ba1051b3b47ccfe17233bf41ef0.png) [@dZh0](https://forums.unrealengine.com/u/dZh0)\
**Post date:** [April 12, 2025, 9:44pm UTC](https://forums.unrealengine.com/t/cascade-raycast/2453531/2 "2025-04-12T21:44:45Z")

</div>

It seems to me that you are not ignoring the origin plane when you launch the second set of rays.

I’m not sure why is that because I can clearly see `Params.AddIgnoredActor(this);` but I’m not fully aware of your whole setup so double check if you are ignoring the correct actor in your second round of ray-traces or weather there is another actor that might be blocking the ray-casts. (some loose plane maybe)

If you are unable to resolve that or you just need a quick and dirty solution:

1. Start your second set of points a set distance after past the hit point.
2. Use `LineTraceMultiByChannel()` and ignore the first hit.

---

<div class="post-metadata">

**Author:** ![pyramidal](https://d3kjluh73b9h9o.cloudfront.net/original/4X/2/8/5/28502927f1d97ba1051b3b47ccfe17233bf41ef0.png) [@pyramidal](https://forums.unrealengine.com/u/pyramidal)\
**Post date:** [April 17, 2025, 11:42am UTC](https://forums.unrealengine.com/t/cascade-raycast/2453531/3 "2025-04-17T11:42:40Z")

</div>

No need to replace LineTraceSingleByChannel with LineTraceMultiByChannel because the utility of LineTraceMultiByChannel does not respond to cascading  
So?

---

<div class="post-metadata">

**Author:** ![dZh0](https://d3kjluh73b9h9o.cloudfront.net/original/4X/2/8/5/28502927f1d97ba1051b3b47ccfe17233bf41ef0.png) [@dZh0](https://forums.unrealengine.com/u/dZh0)\
**Post date:** [April 18, 2025, 10:31pm UTC](https://forums.unrealengine.com/t/cascade-raycast/2453531/4 "2025-04-18T22:31:32Z")

</div>

I’m not really sure what you mean by “does not respond to cascading”. If `LineTraceMultiByChannel()` doesn’t produce a hit, that would be concerning.

Also did you try the other things I’ve suggested?
