I have already expressed it in many replies, but since there are still new people coming in and being confused I decided to dedicate the thread to this topic.
First I need to point out that all numbers I will present later were:
- recorded at Pimax 5k+
- running, PiTool v1.0.1.91
- and firmware v181
They should not change between the different versions, because they are basically defined by the optics, which does not change either, but its good to keep it in mind anyway.
How OpenVR (SteamVR) works
OpenVR subsystem (which is exposed as SteamVR app to the user) uses a headset driver (which is actually a DLL registered by the HMD manufacturer, here Pimax, with the OpenVR during the installation of the HMD software, here PiTool) to detect, initialize, query and use the headset.
The headset driver provides all the necessary characteristics (of the headset) so OpenVR could instruct the application, how it should render the scene. There are two important informations which the app needs:
- View geometry
- Image resolution
View geometry includes the view transformation and the projection matrices for each eye. Those basically define the position and the orientation of the eye/view (transformation matrix) and the single eye FOV (projection matrix).
Image resolution defines the quality of the image. The image resolution must have the precise aspect ratio which corresponds to the viewing frustum of the projection matrix. The one recommended by the headset driver is what the driver believes should give a balanced performance/visual quality.
While the first (view geometry) is defined by the hardware configuration and is either fixed (e.g. the position of the lenses) or configurable (e.g. the IPD), the second (image resolution) is basically easily modifiable by the user, as long as the modification respects the aspect ratio requirement.
Baseline (a.k.a. the HMD recommended render target resolution)
The HMD recommended render target resolution is typically not directly exposed to the user though it is not difficult to figure out - because it is what is shown in SteamVR video setting if you set the supersampling manual override to 100%. You can also find it written into the log file vrcompositor.txt
at the very beginning when SteamVR starts.
While this value is fixed for example for OG Vive, it is not fixed for Pimax. In particular it depends on:
- Pimax model (5k+ vs 8k)
- PiTool Rendering Quality setting
- PiTool Parallel projection setting
- PiTool FOV setting
For the Pimax I am going to define the baseline recommended render target resolution when PiTool rendering quality is set to 1.0
and the parallel projection is off.
Here is the table how the resolution differs for different FOVs and parallel projection config (Pimax 5k+, PiTool rendering quality at 1.0
).
FOV PP off PP on
Small 2638 x 2633 2787 x 3291
Normal 3202 x 2633 3852 x 3291
Large 4267 x 2633 6949 x 3291
We can see that the change from the parallel projection off to on is different in vertical and horizontal dimensions for different FOVs. This is because of how parallel projection works and is explained elsewhere (All the parallel FOVs of Pimax 5k+).
I have seen people asking, how is it possible that those resolutions do not relate to the physical panel resolution.
There is no direct relation between the physical panel resolution and the recommended render target resolution
Why is that?
1. Pre-lens warp transformation
First, the headset requires higher resolution image than the panel res, because it must warp the image before it is shown on the panels and the pre-lens warp transformation needs more pixels in order to not lose precision.
It kind of works like a supersampling, except that the warp is not linear (as it must compensate for pincushion distortion of the lenses by adding barrel distortion to the image) so there is no linear scaling of the image.
This explains why there is no favorite factor for supersampling, because the non-linear aspect of the warp basically applies different supersampling factors to the different part of the image.
2. Different FOV configuration
Since Pimax offers different FOV configuration, it cannot use the full horizontal resolution of the panel for each, because the optics is fixed. So if the largest FOV maxes the panel out, the smaller FOVs can use only the proportional res.
3. Hardware IPD setting
While the lenses move when adjusting the hardware IPD, the panels don’t. So in order to accommodate the full IPD range the headset must reserve enough space at the both ends of the panel to allow the repositioning of the image according to the IPD settings.
Here is an example of the image rendered at the baseline resolution (PP off, PiTool 1.0, Normal FOV) by the app (Beat Saber):
You can notice that the resolution of the image is 3202x2633
which confirms the value in the table above and that the used part (where the game image is rendered) fills fully both the horizontal and the vertical resolutions (except the black areas in the corners, which are explicitly avoided by the renderer as instructed by the headset driver by supplying the hidden area mask). In other words, the renderer, being given the resolution, could not be more efficient.
Here is, how this picture looks after the pre-lens warp transformation is applied:
You may notice that the image is indeed distorted with the barrel distortion. (Better illustration of the barrel distortion is here Pimax native projection and pre-lens warp transformation).
What is appalling are the large black areas on the left and right, because these are actually unused. The left area is caused by using reduced (Normal) FOV, the right area is related to my hardware IPD setting (~70 mm) and is close to the limit the headset can handle. Lesser IPD will move the image closer to the right side.
The Important thing to point out here is that while there is a lot of unused pixels, they are not wasting the GPU performance, because the app is never rendering there. The only exception is the chaperon grid, which is rendered as an overlay by OpenVR and apparently does not respect the hidden area mask. But for what the app rendering concerns the optimization is pretty good.
How the user can change the baseline resolution and how the different supersampling factors combine?
PiTool Rendering Quality
First change is possible in PiTool, by changing the Rendering Quality. The formula which applies here is factor by the dimensions. I.e.:
Let (X, Y)
be the baseline res, reported by the headset (when PiTool RQ is at 1.0
)
Let RQ
be the new rendering quality set in PiTool
The new resolution is (RQ*X, RQ*Y)
.
The new pixel count is RQ^2*X*Y
.
This is important to keep in mind, because the SteamVR supersampling factors work differently (factors the total pixel count, instead of the image dimensions).
SteamVR global SS factor
Let (X, Y)
be the baseline res, reported by the headset (PiTool RQ at 1.0
)
Let S
be the SteamVR supersampling factor
The new resolution is (sqrt(S)*X, sqrt(S)*Y)
The new pixel count is S*X*Y
Which means that SteamVR SS factor can counter PiTool RQ factor, and it does, when using automatic SS adjusting in SteamVR!
If you let SteamVR to auto adjust the SS factor for you it will basically run a benchmark and then adjust the SS so that the total pixel count ensures that the rendering time remains below 11 ms (~90 Hz for Pimax 5k+).
In other words, if you increase PiTool RQ
(and do not change your GPU), SteamVR will decrease the SS correspondingly by 1/(RQ^2)
.
SteamVR application specific SS factor
Apart from the global SS setting in SteamVR, there is also an application specific setting, which is just “personalized” version for the individual app. For each app (which is recognized by SteamVR) the final SS factor is a simple multiplication of the two:
Let SS_g
be SteamVR global supersampling factor
Let SS_a
be application specific supersampling factor
The applied SS factor will be: SS = SS_g * SS_a
Let (X, Y)
be the baseline resolution (recommended by the headset).
The new resolution recommended to the app by OpenVR is:
(sqrt(SS_g)*sqrt(SS_a)*X, sqrt(SS_g)*sqrt(SS_a)*Y)
The new pixel count recommended to the app: SS_g*SS_a*X*Y
Total formula
Combining all the information from above we can determine what will be the recommended render target resolution (pixel count) to the app by OpenVR:
Let (X, Y)
be the baseline res, reported by the headset (when PiTool RQ is at 1.0
)
Let RQ
be the new rendering quality set in PiTool
Let SS_g
be SteamVR global supersampling factor
Let SS_a
be application specific supersampling factor
The new recommended render target resolution to the app by OpenVR is:
(sqrt(SS_g)*sqrt(SS_a)*RQ*X, sqrt(SS_g)*sqrt(SS_a)*RQ*Y)
The new pixel count will be: RQ^2*SS_g*SS_a*X*Y
Do not forget though that the recommended render target resolution to the app by OpenVR is just that - recommended - and the app is free to choose a different one (Recommended render target resolution is just that - recommended).