Setting asymmetric truncation

I have a program in which I track the position of the user and set the truncation (setting the camera to the position of the user) to change the perspective of the scene in accordance with the position of the user. So far, I had all four corners of the display screen on the same z, and I was able to set an asymmetric truncation and change the scene in accordance with the user's perspective.

The current code looks something like this:

UserCam::begin(){ saveGlobalMatrices(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(_topLeftNear.x, _bottomRightNear.x, _bottomRightNear.y, _topLeftNear.y, _camZNear, _camZFar); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(_wcUserHead.x, _wcUserHead.y, _topLeftScreen.z, _wcUserHead.x, _wcUserHead.y, _topLeftScreen.z-1, 0, 1, 0); } UserCam::end(){ loadGlobalMatrices(); } UserCam::setupCam(){ this->_topLeftScreen = _wcTopLeftScreen - _wcUserHead; //wcTopLeftScreen, wcBottomRightScreen and wcUserHead are in the same frame of reference this->_bottomRightScreen = _wcBottomRightScreen - _wcUserHead; this->_topLeftNear = (_topLeftScreen/ _topLeftScreen.z) * _camZNear; this->_bottomRightNear = (_bottomRightScreen/_bottomRightScreen.z )) * _camZNear; } 

However, I want to be able to do the same with a display that remains oblique to the user and / or does not have all of its vertices in the same Z

enter image description here The above can be represented as a kind of inclined window, the vertices of which will have a truncation defined from the user's position. How is such a truncation possible when the display does not have all the vertices in the same Z ?

EDIT
There are three planes in the installation that I am considering. The middle ones give the correct asymmetric truncation, since all the vertices are on the same Z, while the left and right planes have two vertices, each of which has different Z. The vertices of them are as follows:

 Plane1: TL : (-426.66, 0, 200), TR: (0, 0, 0), BL : (-426.66, 320.79, 200), BR : (0, 320.79, 0) Plane2: TL : (0, 0, 0), TR: (426.66, 0, 0), BL : (0, 320.79, 0), BR: (426.66, 320.79, 0) Plane3: TL: (426.66, 0, 0), TR: (853.32, 0, 200), BL : (426.66, 320.79, 0), BR : (853.32, 320.79, 200) 
+4
source share
1 answer

The idea in this setup is to convert it to the case where all angles have the same z coordinate. This is usually done with a view matrix, and you get:

 overall_transform = (projection) * (view * world) 

or in OpenGL wording

 overall_transform = projection * modelview 

If you do not want to interfere with the original model view matrix, you must enter a different matrix between them:

 overall_transform = (projection * adaption) * (view * world) 

where adaption is a rotation matrix that displays the corners of the screen in a plane with a constant z-coordinate.

To find the right options for projection , you need to transform the screen using adaption .

Edit

Let's start with an arbitrary scene where the camera position, direction and screen are known. We believe that model matrices already exist for each object:

Initial situation

Then we need a transformation of the form V , which aligns the camera with the beginning. This matrix is ​​easily calculated using gluLookAt . The general matrix is ​​then T = V * M :

After view transformation

Prior to this step, the matrices are the same for all three screens. Therefore, this part should be in the model viewing matrix. Now we are adding to the projection matrix because it differs on the screen.

We need to apply the rotation R , which aligns the screen perpendicular to the z axis. The position of the camera should not change at this stage, since it represents the center of the projection. The general transformation is now T = R * V * M

To calculate the angle, we can use, for example, atan2 :

 dx = right.x - left.x dz = right.z - left.z angle = atan2(dz, dx) 

You may need to adapt this calculation a little to your actual needs.

After rotation adaption

It is time to apply the actual perspective transformation that can be done with glFrustum .

We need to find the local edges of the screen. You can convert the screen coordinates using the current conversion ( R * V ).

 TL' = R * V * TL BL' = R * V * BL BR' = R * V * BR 

Now all three coordinates should have the same z coordinate. We can use them as follows:

 common_z = TL'.z = BL'.z = BR'.z glFrustum(TL'.x / common_z * z_near, BR'.x / common_z * z_near, BL'.y / common_z * z_near, TL'.y / common_z * z_near, z_near, z_far) 

So, the general T = glFrustum * R * V * M :

 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(...); //any further model transforms glMatrixMode(GL_PROJECTION); glFrustum(...); glRotate(...); 
+6
source

Source: https://habr.com/ru/post/1490848/


All Articles