The intensity of the pointlight is not updated in C ++

Hi,i’m using UE 5.02.
I have attached a UPointLightComponent to a custom Actor in the Actor constructor e i have set here all parameters like intensity,attenuation … and mobility = “Movable”
I need to change intensity during the game,but when i try to change it,numerically,intensity takes the assigned value but I don’t see any effect.
To see the effect,I have to change something in the details panel, no matter what.
i don’t undestand why this happens.
Has anyone encountered a similar problem?

Could you share the relevant code?

This is the code for light creation inside the constuctor of actor “MyTerra”
(I’m just doing tests, so don’t give meaning to the names used)

    root = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
SetRootComponent(root);
earth = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Earth"));


static ConstructorHelpers::FObjectFinder<UStaticMesh>MeshAsset(TEXT("StaticMesh'/Game/terra.terra'"));

earthMesh = MeshAsset.Object;
if (MeshAsset.Object)
{
	
	earth->SetStaticMesh(earthMesh);
}

earth->SetupAttachment(root);
earth->SetRelativeLocation(FVector(0, 0, 0));   

PointLight = CreateDefaultSubobject<UPointLightComponent>(TEXT("Point Light"));
PointLight->SetupAttachment(earth);
PointLight->bUseRayTracedDistanceFieldShadows = true;
PointLight->Intensity = 100000;
PointLight->AttenuationRadius = 1000000;
PointLight->SetMobility(EComponentMobility::Movable);

This is the code to change light intensity. (arr0 is a TArray<AActor*> , lig is UPointLightComponent* ). I’ve tried in BeginPlay function of my GameMode class,but the result is the same everywhere,even in BeginPlay function of the main actor MyTerra:

UGameplayStatics::GetAllActorsOfClass(GetWorld(), AMyTerra::StaticClass(), arr0);
AActor* atr{ nullptr };
atr = arr0.FindByPredicate([](AActor act) { return (Cast(act))->GetName() == “MyTerra_0”; });
// atr is the owner of UPoinLightComponent
if (atr != nullptr)
{
lig = atr->FindComponentByClass();

		if (lig != nullptr)
		{
			
			lig->SetMobility(EComponentMobility::Movable);    // again
			lig->Intensity = 300;
			lig->SetIntensity(300);  // just to try
			
		}

Note .In my code i have specified the class UPointLightComponent after FindComponentByClass but here this part is ignored in the post.In my code the class UPointLightComponent is not missing,

Compilation is ok,no errors,but no effects.

Summary: Invoke the method RecreateRenderState_Concurrent in your light component somewhere during the actor’s BeginPlay.


Hey, tried doing a similar thing (but using a DirectionalLight) in a project, and also bumped into this issue. Pretty sure it’s an oversight in the initialization of LightComponents in the engine, since they are rarely created from C++ (when added in Blueprints, these components don’t suffer from this issue).

I found out that the reason why the light is not updating is that the MarkRenderStateDirty call that eventually happens when you invoke SetIntensity (and similar methods) exits early because the render state is not created.

The issue seems to lie in the component’s registration, which executes this private method (irrelevant code omitted):

void UActorComponent::ExecuteRegisterEvents(FRegisterComponentContext* Context)
{
	...

	if (FApp::CanEverRender() && !bRenderStateCreated && WorldPrivate->Scene && ShouldCreateRenderState())
	{
		...
		CreateRenderState_Concurrent(Context);
		...
	}

	...
}

The problem arises with that WorldPrivate->Scene, which will be null during the constructor’s execution (this check likely happens too early, such that the world is not fully initialized), and thus the render state will not be created. This is not usually a problem with meshes and the like because these recreate the render state somewhere during BeginPlay.


So the simplest solution seems to be just that, stick the following line:

PointLight->RecreateRenderState_Concurrent();

somewhere in your actor’s BeginPlay and you should be good to go.

No need to worry about the weird name, the “Concurrent” suffix simply indicates that the RenderState will be created by a separate thread at a later moment.

Note: You should prefer SetIntensity and similar methods to directly modifying the component’s properties, since the methods will do more stuff in the background, including invoking MarkRenderStateDirty, which you will need to do manually otherwise.

1 Like

The SetIntensity() function is the key. I think this calling this function calls the renderer thread too.
Thank you.