Questions about reflections

Discussion area about developing with Ogre-Next (2.1, 2.2 and beyond)


Post Reply
User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 267
Joined: Wed Apr 23, 2014 3:49 pm
Location: Bologna, Italy
x 75
Contact:

Questions about reflections

Post by TaaTT4 »

Working on porting my engine to OGRE 2.2, I'm wondering if I'll also be able to improve reflections in the meanwhile.

Waiting to add SSR, this is the situation atm:
Image

You can see:
  • The circuit in gray (for who didn't know, I'm working on a racing game)
  • The box in yellow
  • The car over the track
You can also see three different cubemaps used for reflections:
  • The red one is static (is rendered once at scene beginning), has its center at world origin and encloses all the scene. It's used as a "global reflection map" for pretty much all the objects.
  • The blue one is static too, is centered at the barycenter of the box and encloses it. It's used as a reflection map for all the objects inside the box.
  • The green one instead is dynamic (is rendered at every frame) and is "attached" to the car. It's used to reflect car surroundings on it.
I've implemented a (simple!) probe/reflection system in my engine before the PCC came out in OGRE. This system basically mimic what Sample_Tutorial_DynamicCubemap does. The main difference is that for static reflections the rendering happens just at the beginning of the scene (or on demand).

With the transition to OGRE 2.2, I aim to use PCC for static reflections. My only concern is if they work good even with huge probes. For example, in my scenario the red probe has a side of about 10000 units (meters). Is it too much for a PCC?

Always speaking about reflections, how do you solve/mitigate the "reflection inception" issue? This is what I mean:
  1. Object "O" is rendered to cubemap "C"
  2. Cubemap "C" is binded to object "O" material as a reflection map
  3. Object "O" is rendered to render target/window
At step "a" the object is rendered very dark since its material has no specular information at all. Obviously, this cause the reflection cubemap to being dark too. At step "c", when the object will use the cubemap as a reflection map, it will appear darker than it should be.

In my case, this is particularly noticeable inside the box:
Image
Image

The box is illuminated by two spotlights coming from the top and, as you can see, the upper part of the cubemap is completely dark.

I believe this is a very common problem, but I don't even know how to query Google for it. Not totally sure of it, but I guess that baking lightmaps offline or using GI are THE solution. Unfortunately, I doubt I can afford these techniques.

Senior programmer at 505 Games; former senior engine programmer at Sandbox Games
Worked on: Racecraft EsportRacecraft Coin-Op, Victory: The Age of Racing

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5299
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1279
Contact:

Re: Questions about reflections

Post by dark_sylinc »

With the transition to OGRE 2.2, I aim to use PCC for static reflections. My only concern is if they work good even with huge probes. For example, in my scenario the red probe has a side of about 10000 units (meters). Is it too much for a PCC?
Size shouldn't be a problem for PCC.

If you're using per pixel probes, beware it's like lights: big PCC means they end up being processed by every pixel, everywhere.
Always speaking about reflections, how do you solve/mitigate the "reflection inception" issue? This is what I mean:
The quick answer: Raytracing. These techniques are all smoke and mirror tricks.

The longer answer:
  1. You can use fake hemi ambient light only during the cubemap generation pass
  2. Like previous step, but using a fully static cubemap
  3. Using CubemapProbe::mNumIterations parameter. With each iteration, we generate again the cubemap probe but using the cubemap from the previous iteration, hence gaining this information we're missing. The higher the number of iterations, the longer it takes to generate the cubemap. There's also another problem: cubemaps with iteration don't really look good once you move the camera too much away from the probe's camera position; multi-bounce reflections stop looking like mirrors and instead start looking like cardboard (because the reflections embeded in the probe don't react to the camera's position) unless you generate the probe every frame. But doing that with more than one iteration can be expensive. Another solution is to simply mask out all specular from probes. Note: I can't remember if Per-pixel PCC supported num_iteration (it may not)
So yeah, the real solution is true raytracing for everything.
You can play with the iteration parameters in our samples.
User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 267
Joined: Wed Apr 23, 2014 3:49 pm
Location: Bologna, Italy
x 75
Contact:

Re: Questions about reflections

Post by TaaTT4 »

dark_sylinc wrote: Wed Oct 02, 2019 8:53 pm If you're using per pixel probes, beware it's like lights: big PCC means they end up being processed by every pixel, everywhere.
Maybe I missed something, is there any reference/docs about per pixel probes? I mean, what's the difference with non per pixel version? Per pixel is "just" an option of PCC or is a totally different beast?
dark_sylinc wrote: Wed Oct 02, 2019 8:53 pm Another solution is to simply mask out all specular from probes.
What are you meaning with this? Could you please explain it a bit more in detail?
dark_sylinc wrote: Wed Oct 02, 2019 8:53 pm So yeah, the real solution is true raytracing for everything.
Fucking raytracing. Everything in this era is solved by raytracing (and by AI) :D I'm a bit scared about GI techniques and maybe they're just "too much" in my scenario (where 95% of the time you are in an outdoor scene). I will experiment a bit with cubemap iterations and with ambient light. Speaking of this, is there any table/formula to map from light specs (color, intensity, attenuation, etc) to plausible ambient light values? I'm asking this because, in theory, I know which light affect which probe and would be great if I were be able to automate all the process.

Senior programmer at 505 Games; former senior engine programmer at Sandbox Games
Worked on: Racecraft EsportRacecraft Coin-Op, Victory: The Age of Racing

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5299
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1279
Contact:

Re: Questions about reflections

Post by dark_sylinc »

TaaTT4 wrote: Wed Oct 02, 2019 10:22 pm Maybe I missed something, is there any reference/docs about per pixel probes? I mean, what's the difference with non per pixel version? Per pixel is "just" an option of PCC or is a totally different beast?
PCC was added in 2.1 (ParallaxCorrectedCubemap), Per-Pixel PCC (ParallaxCorrectedCubemapAuto) was added in 2.2.

With regular PCC, when there are multiple PCC probes that should be active, we perform a very lame "blending" that works better for indoors and corridors.

You can toggle regular with per-pixel in the LocalCubemaps sample with F7.

With per-pixel PCC, you can have as many probes as performance allows, and probe coverage is blended per pixel; which is far more flexible and allows doing a lot of things.
TaaTT4 wrote: Wed Oct 02, 2019 10:22 pm What are you meaning with this? Could you please explain it a bit more in detail?
During cubemap generation, just set specular colour to 0 to all lights, then restore it.
I'm evaluating of making this a simple boolean for users (right now you would have to iterate all lights by hand in a listener).
TaaTT4 wrote: Wed Oct 02, 2019 10:22 pm I'm a bit scared about GI techniques and maybe they're just "too much" in my scenario (where 95% of the time you are in an outdoor scene). I will experiment a bit with cubemap iterations and with ambient light.
That is true. Outdoor scenes have it easy in comparison, specially racing games. You're worrying too much.
In fact I'm not 100% sure how much you benefit from using PCC (particularly during the race; inside pit stops and close to buildings that's another deal).
User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 267
Joined: Wed Apr 23, 2014 3:49 pm
Location: Bologna, Italy
x 75
Contact:

Re: Questions about reflections

Post by TaaTT4 »

I carry on this post with other questions related to reflections :)
  • Can per-pixel PCC(s) be used for dynamic reflections (updated at every frame)? I've seen that there's a CubemapProbe::setStatic method, but in Sample_Tutorial_DynamicCubemap the cubemap is created and rendered by hand. In there any reason behind this choice? Is there any drawback in updating a per-pixel PCC at every frame?
  • Is there a way to show the probe influence area and its shape? I mean, using WireAabb is a bit limiting since it doesn't take in account orientation. Being able to see the probe OBB would help a lot both artists and debugging process.
  • I have the needs to use a custom execution mask for the probe workspace. Can I use the mipmapsExecutionMask param of the CubemapProbe::initWorkspace method for that (even if it's designed for a different purpose)? Please note that I initialize the probe calling CubemapProbe::setTextureParams with useManual equals to true.
  • As optimization for dynamic reflections, I'd like to mimic what Unity calls Time Slicing. Is it feasible in some way? Always related to this, can mipmaps being generated per cubemap face instead of per texture?

Senior programmer at 505 Games; former senior engine programmer at Sandbox Games
Worked on: Racecraft EsportRacecraft Coin-Op, Victory: The Age of Racing

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5299
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1279
Contact:

Re: Questions about reflections

Post by dark_sylinc »

[*] Can per-pixel PCC(s) be used for dynamic reflections (updated at every frame)? I've seen that there's a CubemapProbe::setStatic method
Yes.
Note that we render to a single temporary cubemap, then copy the rendered result to the cubemap array.
We don't render to the array directly so the GPU driver can choose the optimal swizzling pattern for sampling from the texture (it's an optimization unless you plan on updating every probe every frame)
but in Sample_Tutorial_DynamicCubemap the cubemap is created and rendered by hand. In there any reason behind this choice? Is there any drawback in updating a per-pixel PCC at every frame?
Tutorial_DynamicCubemap does not showcase PCC at all. It's an older sample just showing how to render into a cubemap by yourself, something that was requested a lot from users coming from 1.x.
[*] Is there a way to show the probe influence area and its shape? I mean, using WireAabb is a bit limiting since it doesn't take in account orientation. Being able to see the probe OBB would help a lot both artists and debugging process.
Just create a semitransparent unit-length cube and set the transform to match.
Or slightly modify WireAabb so that with a boolean setting you can control the old behavior, and a new one that takes an AABB in local space and considers pos/scale/rotation.

WireAabb was originally meant for debugging AABB (which never rotate), but can be extended to other uses.
[*] I have the needs to use a custom execution mask for the probe workspace. Can I use the mipmapsExecutionMask param of the CubemapProbe::initWorkspace method for that (even if it's designed for a different purpose)? Please note that I initialize the probe calling CubemapProbe::setTextureParams with useManual equals to true.
I have no idea.
We may flip mipmapsExecutionMask (see comments about DPM fallback).

Perhaps it's better to change it to two parameters: executionMask2DArray and executionMaskCubemapArray. So that you have full control.
[*] As optimization for dynamic reflections, I'd like to mimic what Unity calls Time Slicing. Is it feasible in some way? Always related to this, can mipmaps being generated per cubemap face instead of per texture?
I suppose so, but there is no functionally currently set in place for this.
IIRC ParallaxCorrectedCubemapAuto::updateExpensiveCollectedDirtyProbes and CubemapProbe::_updateRender would need changes to account for this.

Regarding mipmapping, we currently rely on API-provided functionality to generate the mipmaps, which is very basic and generates all mips at once. Thus we would need a custom blurring functionality in order to spread it over frames. Though I suspect Unity provides this functionality because they must be using a more expensive blurring filter than the one we provide (high quality filtering a cubemap is an expensive operation)
Post Reply