Hmm, for me the code fires twice per component.
So it finds each light component twice thus breaking the math? Not too sure, will have a deeper look later! Very interesting post! Not fantastic at physics but would the answer be closer to
light = 1 / (distance*distance)*wattage;
??
http://www.portraitlighting.net/inversesquare_law.htm
edit: as i said no expert! My suggestion is clearly wrong! will keep working on this.
Check the component is in world to make it not grab two of each light. Math seems good to me for doing what your doing, i modified it to show 'total light' as i found this more useful.
Announcement
Collapse
No announcement yet.
[CODE SNIPPET - C++] Detecting if Pawn (or any actor) is in light
Collapse
X
-
KoldKam repliedHey! I was rewriting my system so that it calculates the amount of light on the player accurately, but I don't think my math is right. Could any of you check it out or give any suggestions?
Code:bool ABaseCharacter::GetLightingCondition() { // Define a variable for the final result to be stored in, bool bLit = false; float averageLight = 0; int32 lightsFound = 0; // Loop through all lights, for (TObjectIterator<ULightComponent> Itr; Itr; ++Itr) { // If this light is valid, if (!IsValid(Itr->GetOwner())) continue; // If this light is not a default object, if (Itr->GetOwner()->HasAnyFlags(RF_ClassDefaultObject)) continue; // If this light is enabled (or visible), if (!Itr->IsVisible()) continue; // If the light affects this character's capsule component, if (!Itr->AffectsPrimitive(GetCapsuleComponent())) continue; // If a line trace test from the light's position to the character's position does not hit any actor, if (GetWorld()->LineTraceTest(Itr->GetComponentLocation(), GetActorLocation(), ECC_Visibility, FCollisionQueryParams(NAME_None, true, Itr->GetOwner()))) continue; lightsFound += 1; switch (Itr->GetLightType()) { case ELightComponentType::LightType_Directional: { UDirectionalLightComponent* directionalLight = Cast<UDirectionalLightComponent>(*Itr); averageLight += directionalLight->Intensity / 17; break; } case ELightComponentType::LightType_Point: { UPointLightComponent* pointLight = Cast<UPointLightComponent>(*Itr); float wattage = pointLight->Intensity / 17; float distance = FVector::Dist(GetActorLocation(), Itr->GetComponentLocation()) / 100; float surfaceArea = 4 * PI * FMath::Square(distance); float light = FMath::Clamp<float>(wattage / surfaceArea, 0, 1); averageLight += light; break; } case ELightComponentType::LightType_Spot: { USpotLightComponent* spotLight = Cast<USpotLightComponent>(*Itr); float wattage = spotLight->Intensity / 17; float distance = FVector::Dist(GetActorLocation(), Itr->GetComponentLocation()) / 1000; float slantLength = FMath::Sqrt(FMath::Square(spotLight->AttenuationRadius) + FMath::Square(spotLight->AttenuationRadius)); float surfaceArea = (PI * FMath::Square(distance)) + (PI * distance * slantLength); float light = FMath::Clamp<float>(wattage / surfaceArea, 0, 1); averageLight += light; break; } } /* Draw a Debug Line to show how the light is hitting the character,*/ DrawDebugLine(GetWorld(), Itr->GetComponentLocation(), GetActorLocation(), FColor::Yellow); // The player is in light, so set "lit" to true. bLit = true; } // Average, averageLight /= lightsFound; // Round average light to nearest tenth, if (averageLight != 0.0f) averageLight = FMath::FloorToFloat(averageLight * 100 + 0.5f) / 100; GEngine->AddOnScreenDebugMessage(-1, 0.01f, FColor::White, FString::SanitizeFloat(averageLight)); // Return final result. return bLit; }
Leave a comment:
-
n00854180t repliedOriginally posted by KoldKam View PostThanks guys! And thanks for the suggestion! It looks a trillion times neater. I've updated the post with the neater version. I will start using this for other mechanics that require a loop!
Leave a comment:
-
KoldKam repliedThanks guys! And thanks for the suggestion! It looks a trillion times neater. I've updated the post with the neater version. I will start using this for other mechanics that require a loop!
Leave a comment:
-
n00854180t repliedGreat addition!
One suggestion for the code is to change this part so that the conditions are reversed
Code:// For every light component, for (TObjectIterator<ULightComponent> Itr; Itr; ++Itr) { // If this light is enabled (or visible), if (Itr->IsVisible()) { // If the light type is not directional, if (Itr->GetLightType() != LightType_Directional) { // If the light affects this character's capsule component, if (Itr->AffectsPrimitive(CapsuleComponent)) { // If a line trace test from the light's position to the character's position does not hit any actor, if (!GetWorld()->LineTraceTest(Itr->GetComponentLocation(), GetActorLocation(), ECC_Visibility, FCollisionQueryParams(true))) { // *** Draw a Debug Line to show how the light is hitting the player, DrawDebugLine(GetWorld(), Itr->GetComponentLocation(), GetActorLocation(), FColor::Yellow); // The player is in light, so set "lit" to true. lit = true; } } } } }
Code:// For every light component, for (TObjectIterator<ULightComponent> Itr; Itr; ++Itr) { // If this light is not enabled (or visible) go to next, if (!Itr->IsVisible()) continue; // If the light type IS directional, go to next, if (Itr->GetLightType() == LightType_Directional) continue; // If the light does not affectsthis character's capsule component, go to next, if (!Itr->AffectsPrimitive(CapsuleComponent)) continue; // If a line trace test from the light's position to the character's position does not hit any actor, if (!GetWorld()->LineTraceTest(Itr->GetComponentLocation(), GetActorLocation(), ECC_Visibility, FCollisionQueryParams(true))) { // *** Draw a Debug Line to show how the light is hitting the player, DrawDebugLine(GetWorld(), Itr->GetComponentLocation(), GetActorLocation(), FColor::Yellow); // The player is in light, so set "lit" to true. lit = true; } }
Makes the code quite a bit more readable.
Nice work!Last edited by n00854180t; 08-17-2014, 07:38 PM.
Leave a comment:
-
Staruwos2 repliedThanks KoldKam! That will help those who want to create a stealth game
Leave a comment:
-
[CODE SNIPPET - C++] Detecting if Pawn (or any actor) is in light
Hello all! This is in C++, and the code you see below is actually setup in my Character class in which I derive all my characters from, but you can move it other classes (I recommend creating a base class with this code in it that way, you can check the lighting condition of any object derived from that base class).
H:
Code:virtual void Tick(float DeltaSeconds) override; /* Handle Light Detection */ void HandleLightDetection(); /* Does this character look for light? */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Character") bool bCheckLightingCondition; /* Is this character in light? */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Character") bool bIsInLight;
Code:void AABCharacter::Tick(float DeltaSeconds) { // Call Super::Tick, Super::Tick(DeltaSeconds); // Handle Light Detection. HandleLightDetection(); } /* Handle Light Detection */ void AABCharacter::HandleLightDetection() { // If "CheckLightingCondition" is true, if (bCheckLightingCondition) { // Write "bIsInLight" to the screen as a message, GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Yellow, FString::FromInt(bIsInLight)); // Create a bool that will tell if any light is actually affecting the player or if the player is in any of the lights, bool lit = false; // [THANKS TO RAMA FOR THE ARTICLE ABOUT THIS! :D] For every light component, for (TObjectIterator<ULightComponent> Itr; Itr; ++Itr) { // THANKS TO N00854180T FOR MAKING THE CODE SO MUCH NEATER :D // // If this light is enabled (or visible), if (!Itr->IsVisible()) continue; // If the light type is not directional, if (Itr->GetLightType() == LightType_Directional) continue; // If the light affects this character's capsule component, if (!Itr->AffectsPrimitive(CapsuleComponent)) continue; // If a line trace test from the light's position to the character's position does not hit any actor, if (GetWorld()->LineTraceTest(Itr->GetComponentLocation(), GetActorLocation(), ECC_Visibility, FCollisionQueryParams(true))) continue; // Draw a Debug Line to show how the light is hitting the player, DrawDebugLine(GetWorld(), Itr->GetComponentLocation(), GetActorLocation(), FColor::Yellow); // The player is in light, so set "lit" to true. lit = true; } // If "lit", if (lit) { // Set "bIsInLight" to true, bIsInLight = true; // And prevent "bIsInLight" from being set to false by returning. return; } // Only set to false if "lit" is not equal to true. bIsInLight = false; } }
That little spotlight right there is actually a flashlight, lol
Now I'm running in front of the flashlight
Anyways, I just thought this was pretty cool and I hope this will be useful to someone!Later!
Last edited by KoldKam; 08-17-2014, 07:41 PM.Tags: None
Leave a comment: