x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

Accessing indrect lighting with C++ ?

Hi,

I was thinking about a stealth game mechanic and I was wondering if it was possible to access the indirect lighting cache in any way to compute a sort of local lighting brightness. The goal would be to know if the player is exposed to any lighting and indirect lighting since the purpose is to dissimulate yourself in the shadows.

The best case I think would be to be able to query a bunch of the samples created by lightmass which are near the player. This way it will be possible to compute an average color value and therefor brightness.

Product Version: Not Selected
Tags:
more ▼

asked Mar 11 '14 at 02:13 AM in C++ Programming

avatar image

ue4-archive ♦♦ STAFF
49.9k 3662 1986 9113

(comments are locked)
10|2000 characters needed characters left

1 answer: sort voted first

It's not possible to get at the indirect lighting cache because that's on the rendering thread, but you can interpolate the indirect lighting yourself on the game thread, and then incorporate that into your gameplay. Check out FPrecomputedLightVolume and InterpolateIncidentRadiancePoint, which is exposed to other dll's. To get the correct result you have to interpolate from all levels and combine, along the lines of this, except you want to iterate over levels in the world, each of which potentially has a PrecomputedLightVolumes.

    FSHVectorRGB2 AccumulatedIncidentRadiance;
     float AccumulatedDirectionalShadowing = 0;
     float AccumulatedWeight = 0;
 
     for (int32 VolumeIndex = 0; VolumeIndex < Scene->PrecomputedLightVolumes.Num(); VolumeIndex++)
     {
         const FPrecomputedLightVolume* PrecomputedLightVolume = Scene->PrecomputedLightVolumes[VolumeIndex];
         PrecomputedLightVolume->InterpolateIncidentRadiancePoint(
             Block.Min + Block.Size / 2, 
             AccumulatedWeight, 
             AccumulatedDirectionalShadowing,
             AccumulatedIncidentRadiance);
     }
 
     if (AccumulatedWeight > 0)
     {
         OutDirectionalShadowing = AccumulatedDirectionalShadowing / AccumulatedWeight;
         OutIncidentRadiance = AccumulatedIncidentRadiance / AccumulatedWeight;
     }
     else
     {
         OutIncidentRadiance = AccumulatedIncidentRadiance;
         OutDirectionalShadowing = AccumulatedDirectionalShadowing;
     }
more ▼

answered Mar 11 '14 at 02:13 AM

avatar image

ue4-archive ♦♦ STAFF
49.9k 3662 1986 9113

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:13 AM

I'm trying your code in my character class. Unfortunately it seems my build doesn't know the array "PrecomputedLightVolumes" that should be present inside FSceneInterface.

I'm not sure to follow you by the way when you talk about "exposed to other dll's", what do you mean ? Also, when you talk about interpolating between levels you mean on the currently streamed levels loaded by the game ?

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:13 AM

I was saying you need to change the above code so it iterates over the levels in the world instead of the precomputed light volumes in the scene. Level->PrecomputedLightVolume is the data you want to use for interpolation.

I'm not sure to follow you by the way when you talk about "exposed to other dll's", what do you mean ?

Your game module can only link calls to functions in engine that have been properly exported with ENGINE_API. InterpolateIncidentRadiancePoint is, so you are good to go.

Also, when you talk about interpolating between levels you mean on the currently streamed levels loaded by the game ?

Yes. You can have multiple levels loaded due to level streaming, and they can each have lighting samples. You need to interpolate between all of them to be seamless. The above code shows one way to do this, by accumulating the weight separately from the lighting and then normalizing.

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:13 AM

Thanks for the answer, I'm still trying to convert your sample code to something usable in my Character class. This is what I have so far :

 void AExedreCharacter::ComputeLightWeight()
 {
     
     if(MeshBody != NULL)
     {
         float OutIncidentRadiance = 0.0;
         
         class ULevel* Level = MeshBody->GetComponentLevel();
         
         FSHVectorRGB2 AccumulatedIncidentRadiance;
         
         float AccumulatedWeight = 0;
 
         class FPrecomputedLightVolume* RadianceVolume = Level->PrecomputedLightVolume;
 
         RadianceVolume->InterpolateIncidentRadiance(
         GetActorLocation(), 
         AccumulatedWeight,
         AccumulatedIncidentRadiance);
 
         
         if (AccumulatedWeight > 0)
         {
             OutIncidentRadiance = AccumulatedIncidentRadiance / AccumulatedWeight;
         }
         else
         {
             OutIncidentRadiance = AccumulatedIncidentRadiance;
         }

             //log writing
         elog(OutIncidentRadiance);
     }
 }


Unfortunately I don't pass the compilation. FPrecomputedLightVolume give me an error, the call to InterpolateIncidentRadiance() should be correct, but the compile is complaining. I don't see why because this is what I have in PrecomputedLightVolume.h :

    /** Interpolates incident radiance to Position. */
     ENGINE_API void InterpolateIncidentRadiance(
         const FVector& Position, 
         float& AccumulatedWeight,
         FSHVectorRGB2& AccumulatedIncidentRadiance) const;
     
     /** Interpolates incident radiance to Position. */
     ENGINE_API void InterpolateIncidentRadiance(
         const FBoxCenterAndExtent& BoundingBox, 
         const FIntVector& QueryCellDimensions,
         const FIntVector& DestCellDimensions,
         const FIntVector& DestCellPosition,
         TArray& AccumulatedWeights,
         TArray& AccumulatedIncidentRadiance) const;


Also, the FSHVectorRGB2 / float is also refused by the compiler. Since this struct (I believe) is not explained anywhere, I have no idea how to access its members.

The compiler log :

 D:\Dropbox\Software\notepad\bin>echo OFF
 
 "Building Rocket (Exedre), please wait..."
 
 Parsing headers for Exedre
 Code generation finished for Exedre and took 1,969
 Module.Exedre.cpp
 C:\Rocket\Projects\Exedre\Source\Exedre\Private\ExedreCharacter.cpp(464) : error
  C2027: use of undefined type 'FPrecomputedLightVolume'
         c:\rocket\engine\intermediate\builddata\include\engine\../../../../Sourc
 e/Runtime/Engine/Classes/Engine/Level.h(346) : see declaration of 'FPrecomputedL
 ightVolume'
 C:\Rocket\Projects\Exedre\Source\Exedre\Private\ExedreCharacter.cpp(464) : error
  C2227: left of '->InterpolateIncidentRadiance' must point to class/struct/union
 /generic type
 C:\Rocket\Projects\Exedre\Source\Exedre\Private\ExedreCharacter.cpp(472) : error
  C2440: '=' : cannot convert from 'TSHVectorRGB' to 'float'
         with
         [
             MaxSHOrder=2
         ]
         No user-defined-conversion operator available that can perform this conv
 ersion, or the operator cannot be called
 C:\Rocket\Projects\Exedre\Source\Exedre\Private\ExedreCharacter.cpp(476) : error
  C2440: '=' : cannot convert from 'FSHVectorRGB2' to 'float'
         No user-defined-conversion operator available that can perform this conv
 ersion, or the operator cannot be called
 -------- End Detailed Actions Stats --------------------------------------------
 ---------------
 ERROR: UBT ERROR: Failed to produce item: C:\Rocket\Projects\Exedre\Binaries\Win
 64\RocketEditor-Exedre.pdb
 Cumulative action seconds (8 processors): 0,00 building projects, 10,06 compilin
 g, 0,00 creating app bundles, 0,00 generating debug info, 0,00 linking, 0,00 oth
 er
 UBT execution time: 15,63 seconds
 
 Appuyez sur une touche pour continuer...
avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:13 AM

The first error means you need to include the appropriate header file to get access to the type FPrecomputedLightVolume, like so

 #include "PrecomputedLightVolume.h"

Let me know what the errors are after fixing that.

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:13 AM

Ha, I never thought I had to include the header since the rest of the time the compiler seems to find everything by itself. Thanks !

Now my only and current error is the same as above about the FSHVectorRGB2 conversion to float.

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:13 AM

The conversion error is because you made OutIncidentRadiance a float. FSHVectorRGB2 is a directional HDR color representation so it can't be converted straight to a float. If you only care about brightness in the end (no color) you should do

 FSHVector2 Ambient = FSHVector2::AmbientFunction();
 OutIncidentRadiance  = Dot(AccumulatedIncidentRadiance, Ambient).GetLuminance();

(I didn't actually compile this so might be a typing error)

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:13 AM

Again, thanks a lot for the help. It compiled fine ! :)

I'm not sure to fully understand everything so I will ask some more questions (especially because I'm not familiar with the HDR pipeline) :

  • Why do you do a dot product between the indirect lighting and the ambient lighting instead of adding them together ? Isn't the ambient lighting added on the rest of the lighting normally ?

  • Regarding you code above, why is the Dot product so low even when under some strong lighting ? What would be the best to compute a value more human readable ?

  • I took a look inside some of my books and google, but I wasn't able to find some help to understand a bit better what the following means : typedef TSHVector FSHVector2; . I understand the keyword typedef, but not the . From the rest of SHMath.h it looks like an "order", but what does that means exactly ? Is that a sort of array ?

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:13 AM

Why do you do a dot product between the indirect lighting and the ambient lighting instead of adding them together

FSHVector2::AmbientFunction() makes a 'shape', in this case a shape that has uniform intensity in all directions because we want to know the average lighting. We could also have made a cosine lobe around a normal to do normal mapped lighting. The dot product then answers the question 'how much of the captured lighting (AccumulatedIncidentRadiance) coincides with the shape?'

Regarding you code above, why is the Dot product so low even when under some strong lighting ?

I'm not completely sure, but I might have missed a constant scaling factor. You can try multiplying by a tweakable until it looks acceptable for your purposes.

I took a look inside some of my books and google, but I wasn't able to find some help to understand a bit better what the following means : typedef TSHVector FSHVector2; . I understand the keyword typedef, but not the . From the rest of SHMath.h it looks like an "order", but what does that means exactly ? Is that a sort of array ?

FSHVector2 is a 2 band spherical harmonic, which has four floats total (V0 is ambient term, V1-3 are the first directional band). Using spherical harmonics can involve a lot of complex math but the concept of what they do is simple - just think of them as a low resolution cubemap. They store directional information. The more bands it has, the more resolution in the cubemap. Our indirect lighting samples only have 2 bands to reduce memory usage.

As to the C++ question, is the template parameter of the template class TSHVector, which specifies how many bands (orders) there are. TSHVector is implemented to support different numbers of bands, so we don't have to duplicate a bunch of code to support 2 or 3 bands. FVector2D vs FVector and FVector4 could have been implemented this way too but they are not.

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:13 AM

Thanks for the explanation. I had to multiply the Luminance result by 150000 to get something close to 1 in very bright areas. That seems a bit high.

I was wondering if it was possible to access the direct lighting too ? I'm not sure of how UE4 compute dynamic lighting, but in UE3 dynamic object were using SH too isn't it ? Is that possible to access this SH and do a similar luminance computing ?

I would like to avoid to compute the visibility of lights around the player by using a lot of traces.

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:13 AM

150000 is crazy, I'm not sure what's going on.

I was wondering if it was possible to access the direct lighting too ? I'm not sure of how UE4 compute dynamic lighting, but in UE3 dynamic object were using SH too isn't it ? Is that possible to access this SH and do a similar luminance computing ?

Unfortunately no, only static lights will have their direct lighting in the lighting samples. You would have to trace rays to lights to get their shadowing. Dynamic light environments in UE3 no longer exist in UE4, all stationary and movable lights have their contribution calculated dynamically.

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:13 AM

Last time on this topic (I think). I got everything I need working. I'm using Light->LightComponent->GetDirectIntensity() to know if a light is touching/affecting the player. It works with almost every lights, but not on directional lights (at least not the one considered as the sun in my scene). Is that normal ?

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:13 AM

Is the light visible and affecting the world? The only thing special about the directional light version of that function is that it returns black if the light has bVisible=false or bAffectsWorld=false

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:13 AM +

Okay I made a mistake, the function works with the directional light. However, because of a bug I get a lighting information superior to 0 even in the shadow.

I'm talking about this bug : https://rocket.unrealengine.com/questions/4142/advanced-shadowlighting-settings-.html

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:13 AM

Okay I don't know why but I can't add any new comment below the current ones (they get removed automatically).

Is the light visible and affecting the world? The only thing special about the directional light version of that function is that it returns black if the light has bVisible=false or bAffectsWorld=false

I made a mistake, the function works fine but because of the lighting leak currently in my build the function returns a wrong value when the player is inside a shadow. I will work around that by using a LineTrace check. I'm talking about this leak : https://rocket.unrealengine.com/questions/4142/advanced-shadowlighting-settings-.html

(comments are locked)
10|2000 characters needed characters left
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question