asymmetric viewing frustum stereo patch

Developer discussion of experimental fixes, changes, and improvements.

Moderators: Nexuiz Moderators, Moderators

asymmetric viewing frustum stereo patch

Postby zuizme » Tue Jul 01, 2008 1:24 pm

Hi all,

Please, check out this patch for stereo mode, the game is look just like Nvidia stereo driver.
The patch was generated by diff on Ubuntu Hardy. Please, patch into version 2.4.2 engine source. Enjoy!!!

The codes:

diff -c -d
*** MyDownloads/darkplaces/cl_screen.c 2008-04-10 03:03:36.000000000 -0400
--- darkplaces/cl_screen.c 2008-07-01 08:25:30.000000000 -0400
***************
*** 36,47 ****
cvar_t cl_capturevideo_fps = {0, "cl_capturevideo_fps", "30", "how many frames per second to save (29.97 for NTSC, 30 for typical PC video, 15 can be useful)"};
cvar_t cl_capturevideo_number = {CVAR_SAVE, "cl_capturevideo_number", "1", "number to append to video filename, incremented each time a capture begins"};
cvar_t r_letterbox = {0, "r_letterbox", "0", "reduces vertical height of view to simulate a letterboxed movie effect (can be used by mods for cutscenes)"};
- cvar_t r_stereo_separation = {0, "r_stereo_separation", "4", "separation distance of eyes in the world (negative values are only useful for cross-eyed viewing)"};
cvar_t r_stereo_sidebyside = {0, "r_stereo_sidebyside", "0", "side by side views for those who can't afford glasses but can afford eye strain (note: use a negative r_stereo_separation if you want cross-eyed viewing)"};
cvar_t r_stereo_redblue = {0, "r_stereo_redblue", "0", "red/blue anaglyph stereo glasses (note: most of these glasses are actually red/cyan, try that one too)"};
cvar_t r_stereo_redcyan = {0, "r_stereo_redcyan", "0", "red/cyan anaglyph stereo glasses, the kind given away at drive-in movies like Creature From The Black Lagoon In 3D"};
cvar_t r_stereo_redgreen = {0, "r_stereo_redgreen", "0", "red/green anaglyph stereo glasses (for those who don't mind yellow)"};
cvar_t r_stereo_angle = {0, "r_stereo_angle", "0", "separation angle of eyes (makes the views look different directions, as an example, 90 gives a 90 degree separation where the views are 45 degrees left and 45 degrees right)"};
cvar_t scr_zoomwindow = {CVAR_SAVE, "scr_zoomwindow", "0", "displays a zoomed in overlay window"};
cvar_t scr_zoomwindow_viewsizex = {CVAR_SAVE, "scr_zoomwindow_viewsizex", "20", "horizontal viewsize of zoom window"};
cvar_t scr_zoomwindow_viewsizey = {CVAR_SAVE, "scr_zoomwindow_viewsizey", "20", "vertical viewsize of zoom window"};
--- 36,47 ----
cvar_t cl_capturevideo_fps = {0, "cl_capturevideo_fps", "30", "how many frames per second to save (29.97 for NTSC, 30 for typical PC video, 15 can be useful)"};
cvar_t cl_capturevideo_number = {CVAR_SAVE, "cl_capturevideo_number", "1", "number to append to video filename, incremented each time a capture begins"};
cvar_t r_letterbox = {0, "r_letterbox", "0", "reduces vertical height of view to simulate a letterboxed movie effect (can be used by mods for cutscenes)"};
cvar_t r_stereo_sidebyside = {0, "r_stereo_sidebyside", "0", "side by side views for those who can't afford glasses but can afford eye strain (note: use a negative r_stereo_separation if you want cross-eyed viewing)"};
cvar_t r_stereo_redblue = {0, "r_stereo_redblue", "0", "red/blue anaglyph stereo glasses (note: most of these glasses are actually red/cyan, try that one too)"};
cvar_t r_stereo_redcyan = {0, "r_stereo_redcyan", "0", "red/cyan anaglyph stereo glasses, the kind given away at drive-in movies like Creature From The Black Lagoon In 3D"};
cvar_t r_stereo_redgreen = {0, "r_stereo_redgreen", "0", "red/green anaglyph stereo glasses (for those who don't mind yellow)"};
cvar_t r_stereo_angle = {0, "r_stereo_angle", "0", "separation angle of eyes (makes the views look different directions, as an example, 90 gives a 90 degree separation where the views are 45 degrees left and 45 degrees right)"};
+ cvar_t r_stereo_convergence = {CVAR_SAVE, "r_stereo_convergence", "4", "adjust to bring the game out of screen more or less, no negative number please.)"};
cvar_t scr_zoomwindow = {CVAR_SAVE, "scr_zoomwindow", "0", "displays a zoomed in overlay window"};
cvar_t scr_zoomwindow_viewsizex = {CVAR_SAVE, "scr_zoomwindow_viewsizex", "20", "horizontal viewsize of zoom window"};
cvar_t scr_zoomwindow_viewsizey = {CVAR_SAVE, "scr_zoomwindow_viewsizey", "20", "vertical viewsize of zoom window"};
***************
*** 806,812 ****
Cvar_RegisterVariable (&cl_capturevideo_fps);
Cvar_RegisterVariable (&cl_capturevideo_number);
Cvar_RegisterVariable (&r_letterbox);
! Cvar_RegisterVariable(&r_stereo_separation);
Cvar_RegisterVariable(&r_stereo_sidebyside);
Cvar_RegisterVariable(&r_stereo_redblue);
Cvar_RegisterVariable(&r_stereo_redcyan);
--- 806,812 ----
Cvar_RegisterVariable (&cl_capturevideo_fps);
Cvar_RegisterVariable (&cl_capturevideo_number);
Cvar_RegisterVariable (&r_letterbox);
! Cvar_RegisterVariable(&r_stereo_convergence);
Cvar_RegisterVariable(&r_stereo_sidebyside);
Cvar_RegisterVariable(&r_stereo_redblue);
Cvar_RegisterVariable(&r_stereo_redcyan);
***************
*** 1898,1904 ****
void R_Shadow_EditLights_DrawSelectedLightProperties(void);

int r_stereo_side;
!
void SCR_DrawScreen (void)
{
R_Mesh_Start();
--- 1898,1904 ----
void R_Shadow_EditLights_DrawSelectedLightProperties(void);

int r_stereo_side;
! stereoframe_t stereo_frame;
void SCR_DrawScreen (void)
{
R_Mesh_Start();
***************
*** 2218,2234 ****
{
matrix4x4_t originalmatrix = r_refdef.view.matrix;
matrix4x4_t offsetmatrix;
! Matrix4x4_CreateFromQuakeEntity(&offsetmatrix, 0, r_stereo_separation.value * 0.5f, 0, 0, r_stereo_angle.value * 0.5f, 0, 1);
Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);

if (r_stereo_sidebyside.integer)
r_stereo_side = 0;

if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
{
! r_refdef.view.colormask[0] = 1;
! r_refdef.view.colormask[1] = 0;
! r_refdef.view.colormask[2] = 0;
}

if (vid.stereobuffer)
--- 2218,2236 ----
{
matrix4x4_t originalmatrix = r_refdef.view.matrix;
matrix4x4_t offsetmatrix;
! Matrix4x4_CreateFromQuakeEntity(&offsetmatrix, 0, r_stereo_convergence.value * -0.5f, 0, 0, r_stereo_angle.value * 0.5f, 0, 1);
Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);

+ stereo_frame = STEREO_RIGHT;
+
if (r_stereo_sidebyside.integer)
r_stereo_side = 0;

if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
{
! r_refdef.view.colormask[0] = 0;
! r_refdef.view.colormask[1] = r_stereo_redcyan.integer || r_stereo_redgreen.integer;
! r_refdef.view.colormask[2] = r_stereo_redcyan.integer || r_stereo_redgreen.integer;
}

if (vid.stereobuffer)
***************
*** 2236,2252 ****

SCR_DrawScreen();

! Matrix4x4_CreateFromQuakeEntity(&offsetmatrix, 0, r_stereo_separation.value * -0.5f, 0, 0, r_stereo_angle.value * -0.5f, 0, 1);
Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);

if (r_stereo_sidebyside.integer)
r_stereo_side = 1;

if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
{
! r_refdef.view.colormask[0] = 0;
! r_refdef.view.colormask[1] = r_stereo_redcyan.integer || r_stereo_redgreen.integer;
! r_refdef.view.colormask[2] = r_stereo_redcyan.integer || r_stereo_redblue.integer;
}

if (vid.stereobuffer)
--- 2238,2256 ----

SCR_DrawScreen();

! Matrix4x4_CreateFromQuakeEntity(&offsetmatrix, 0, r_stereo_convergence.value * 0.5f, 0, 0, r_stereo_angle.value * -0.5f, 0, 1);
Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);

+ stereo_frame = STEREO_LEFT;
+
if (r_stereo_sidebyside.integer)
r_stereo_side = 1;

if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
{
! r_refdef.view.colormask[0] = r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer;
! r_refdef.view.colormask[1] = 0;
! r_refdef.view.colormask[2] = 0;
}

if (vid.stereobuffer)
*** MyDownloads/darkplaces/gl_backend.c 2008-05-07 03:25:00.000000000 -0400
--- darkplaces/gl_backend.c 2008-07-01 08:07:45.000000000 -0400
***************
*** 16,22 ****
cvar_t gl_lockarrays = {0, "gl_lockarrays", "0", "enables use of glLockArraysEXT, may cause glitches with some broken drivers, and may be slower than normal"};
cvar_t gl_lockarrays_minimumvertices = {0, "gl_lockarrays_minimumvertices", "1", "minimum number of vertices required for use of glLockArraysEXT, setting this too low may reduce performance"};
cvar_t gl_vbo = {CVAR_SAVE, "gl_vbo", "3", "make use of GL_ARB_vertex_buffer_object extension to store static geometry in video memory for faster rendering, 0 disables VBO allocation or use, 1 enables VBOs for vertex and triangle data, 2 only for vertex data, 3 for vertex data and triangle data of simple meshes (ones with only one surface)"};
!
cvar_t v_flipped = {0, "v_flipped", "0", "mirror the screen (poor man's left handed mode)"};
qboolean v_flipped_state = false;

--- 16,22 ----
cvar_t gl_lockarrays = {0, "gl_lockarrays", "0", "enables use of glLockArraysEXT, may cause glitches with some broken drivers, and may be slower than normal"};
cvar_t gl_lockarrays_minimumvertices = {0, "gl_lockarrays_minimumvertices", "1", "minimum number of vertices required for use of glLockArraysEXT, setting this too low may reduce performance"};
cvar_t gl_vbo = {CVAR_SAVE, "gl_vbo", "3", "make use of GL_ARB_vertex_buffer_object extension to store static geometry in video memory for faster rendering, 0 disables VBO allocation or use, 1 enables VBOs for vertex and triangle data, 2 only for vertex data, 3 for vertex data and triangle data of simple meshes (ones with only one surface)"};
! cvar_t r_stereo_separation = {0, "r_stereo_separation", "4", "separation distance of eyes in the world (negative values are only useful for cross-eyed viewing)"};
cvar_t v_flipped = {0, "v_flipped", "0", "mirror the screen (poor man's left handed mode)"};
qboolean v_flipped_state = false;

***************
*** 255,260 ****
--- 255,261 ----
Cvar_RegisterVariable(&gl_vbo);
Cvar_RegisterVariable(&gl_paranoid);
Cvar_RegisterVariable(&gl_printcheckerror);
+ Cvar_RegisterVariable(&r_stereo_separation);
#ifdef NORENDER
Cvar_SetValue("r_render", 0);
#endif
***************
*** 305,310 ****
--- 306,327 ----
R_Mesh_Matrix(&tempmatrix);
}

+ void Setup_StereoView_Frustum (double *leftx, double *rightx, double frustumx, double znear)
+ {
+ double novfcl;

+ novfcl = znear / (110 / frustumx );

+ if(stereo_frame == STEREO_LEFT)

+ {

+ *leftx = -frustumx * znear + r_stereo_separation.value * novfcl ;

+ *rightx = frustumx * znear + r_stereo_separation.value * novfcl ;

+ }
+ if(stereo_frame == STEREO_RIGHT)
+ {

+ *leftx = -frustumx * znear - r_stereo_separation.value * novfcl ;

+ *rightx = frustumx * znear - r_stereo_separation.value * novfcl ;
+ }
+ }
+
static void GL_BuildFrustum(double m[16], double left, double right, double bottom, double top, double nearVal, double farVal)
{
m[0] = 2 * nearVal / (right - left);
***************
*** 330,350 ****

void GL_SetupView_Mode_Perspective (double frustumx, double frustumy, double zNear, double zFar)
{
! double m[16];

// set up viewpoint
CHECKGLERROR
qglMatrixMode(GL_PROJECTION);CHECKGLERROR
// set view pyramid
#if 1
// avoid glGetDoublev whenever possible, it may stall the render pipeline
// in the tested cases (nvidia) no measurable fps difference, but it sure
// makes a difference over a network line with GLX
! GL_BuildFrustum(m, -frustumx * zNear, frustumx * zNear, -frustumy * zNear, frustumy * zNear, zNear, zFar);
qglLoadMatrixd(m);CHECKGLERROR
#else
qglLoadIdentity();CHECKGLERROR
! qglFrustum(-frustumx * zNear, frustumx * zNear, -frustumy * zNear, frustumy * zNear, zNear, zFar);CHECKGLERROR
qglGetDoublev(GL_PROJECTION_MATRIX, m);CHECKGLERROR
#endif
Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
--- 347,388 ----

void GL_SetupView_Mode_Perspective (double frustumx, double frustumy, double zNear, double zFar)
{
! double m[16], left, right;

// set up viewpoint
CHECKGLERROR
qglMatrixMode(GL_PROJECTION);CHECKGLERROR
+
// set view pyramid
#if 1
// avoid glGetDoublev whenever possible, it may stall the render pipeline
// in the tested cases (nvidia) no measurable fps difference, but it sure
// makes a difference over a network line with GLX
!
! //assymetric viewing frustum for stereo mode
!
! if (stereo_frame)

! {
! Setup_StereoView_Frustum (&left, &right, frustumx, zNear);

! GL_BuildFrustum(m, left, right, -frustumy * zNear, frustumy * zNear, zNear, zFar);
! }
! else
! {
! GL_BuildFrustum(m, -frustumx * zNear, frustumx * zNear, -frustumy * zNear, frustumy * zNear, zNear, zFar);
! }
qglLoadMatrixd(m);CHECKGLERROR
#else
qglLoadIdentity();CHECKGLERROR
!
! if (stereo_frame)

! {
! Setup_StereoView_Frustum (&left, &right, frustumx, zNear);

! qglFrustum(left, right, -frustumy * zNear, frustumy * zNear, zNear, zFar);
! }
! else
! {
! qglFrustum(-frustumx * zNear, frustumx * zNear, -frustumy * zNear, frustumy * zNear, zNear, zFar);CHECKGLERROR
! }
qglGetDoublev(GL_PROJECTION_MATRIX, m);CHECKGLERROR
#endif
Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
***************
*** 355,369 ****

void GL_SetupView_Mode_PerspectiveInfiniteFarClip (double frustumx, double frustumy, double zNear)
{
! double nudge, m[16];

// set up viewpoint
CHECKGLERROR
qglMatrixMode(GL_PROJECTION);CHECKGLERROR
qglLoadIdentity();CHECKGLERROR
// set view pyramid
nudge = 1.0 - 1.0 / (1<<23);
! m[ 0] = 1.0 / frustumx;
m[ 1] = 0;
m[ 2] = 0;
m[ 3] = 0;
--- 393,422 ----

void GL_SetupView_Mode_PerspectiveInfiniteFarClip (double frustumx, double frustumy, double zNear)
{
! double nudge, m[16], left, right;

// set up viewpoint
CHECKGLERROR
qglMatrixMode(GL_PROJECTION);CHECKGLERROR
qglLoadIdentity();CHECKGLERROR
+
+ //assymetric viewing frustum for stereo mode
+
+ if (stereo_frame)

+ {

+ Setup_StereoView_Frustum (&left, &right, frustumx, zNear);

+
+ m[ 0] = 2 * zNear / (right - left);

+ m[ 8] = ( right + left ) / (right - left);

+ } else {

+

+ m[ 0] = 1.0 / frustumx;

+ m[ 8] = 0;

+ }
+
// set view pyramid
nudge = 1.0 - 1.0 / (1<<23);
! // m[ 0] = 1.0 / frustumx;
m[ 1] = 0;
m[ 2] = 0;
m[ 3] = 0;
***************
*** 371,377 ****
m[ 5] = 1.0 / frustumy;
m[ 6] = 0;
m[ 7] = 0;
! m[ 8] = 0;
m[ 9] = 0;
m[10] = -nudge;
m[11] = -1;
--- 424,430 ----
m[ 5] = 1.0 / frustumy;
m[ 6] = 0;
m[ 7] = 0;
! // m[ 8] = 0;
m[ 9] = 0;
m[10] = -nudge;
m[11] = -1;
*** MyDownloads/darkplaces/quakedef.h 2008-02-04 07:47:04.000000000 -0500
--- darkplaces/quakedef.h 2008-06-30 11:03:34.000000000 -0400
***************
*** 347,352 ****
--- 347,362 ----

void Sys_Shared_Init(void);

+ typedef enum stereoframe_s
+ {
+ STEREO_CENTER,
+ STEREO_RIGHT,
+ STEREO_LEFT,
+ }
+ stereoframe_t;
+
+ extern stereoframe_t stereo_frame;
+
// Flag in size field of demos to indicate a client->server packet. Demo
// playback will ignore this, but it may be useful to make DP sniff packets to
// debug protocol exploits.
Last edited by zuizme on Tue Jul 01, 2008 3:27 pm, edited 1 time in total.
zuizme
Newbie
 
Posts: 5
Joined: Sun Jun 29, 2008 3:45 pm

Postby Psychcf » Tue Jul 01, 2008 2:07 pm

Awesome!
Psychcf
Forum addon
 
Posts: 1554
Joined: Sun Dec 03, 2006 11:38 pm
Location: NY, USA

Postby divVerent » Tue Jul 01, 2008 2:25 pm

Can you explain WHAT you are doing different and why? Also, can you make a "diff -u" instead (more readable format for me) and post it for download, instead of pasting it into the forum (copypasting out of here breaks it)?

Currently, the stereo separation works by moving the point of view a bit to the left or the right, but keeping the view direction. What did you change? How is it different from what can be achieved by the current cvars?

Thanks
1. Open Notepad
2. Paste: ÿþMSMSMS
3. Save
4. Open the file in Notepad again

You can vary the number of "MS", so you can clearly see it's MS which is causing it.
divVerent
Site admin and keyboard killer
 
Posts: 3809
Joined: Thu Mar 02, 2006 4:46 pm
Location: BRLOGENSHFEGLE

Postby zuizme » Tue Jul 01, 2008 3:05 pm

divVerent wrote:Can you explain WHAT you are doing different and why? Also, can you make a "diff -u" instead (more readable format for me) and post it for download, instead of pasting it into the forum (copypasting out of here breaks it)?

Currently, the stereo separation works by moving the point of view a bit to the left or the right, but keeping the view direction. What did you change? How is it different from what can be achieved by the current cvars?

Thanks




Well, I actually follow Paul Bourke method on the web, but the web page has been updated.
The trick is in the calculation for a off-axis projection before changing the projection matrix and the calculation need the z projection value (some understand as the focal length).
I've made the patch with diff -u, could you show me how to post the file for dowload. Thanks
zuizme
Newbie
 
Posts: 5
Joined: Sun Jun 29, 2008 3:45 pm

Link for download the patch

Postby zuizme » Tue Jul 01, 2008 8:52 pm

Hi all,

Here is the link to download the stereo patch file.

http://www.savefile.com/files/1644074

There's only one new cvar "r_stereo_convergence" for player to adjust the out of screen effect to their own comfort. The r_stereo_separation cvar will increases the stereo depth effect. Do not use the r_stereo_angle, leave it at default 0. Enjoy.
zuizme
Newbie
 
Posts: 5
Joined: Sun Jun 29, 2008 3:45 pm

Postby LordHavoc » Sat Jul 19, 2008 11:29 am

This patch seems to do the following:
1. render right then left rather than left then right.
Why?
2. renames the existing r_stereo_separation to r_stereo_convergence.
Why?
3. implements GL_PROJECTION matrix based stereo separation (using r_stereo_separation rather than r_stereo_convergence) and biases the frustum accordingly.
Why?

Could you explain what the purpose of this patch is?
LordHavoc
Site Admin
 
Posts: 191
Joined: Wed Mar 29, 2006 7:39 am
Location: western Oregon, USA

Postby zuizme » Thu Aug 21, 2008 1:55 am

LordHavoc wrote:This patch seems to do the following:
1. render right then left rather than left then right.
Why?
2. renames the existing r_stereo_separation to r_stereo_convergence.
Why?
3. implements GL_PROJECTION matrix based stereo separation (using r_stereo_separation rather than r_stereo_convergence) and biases the frustum accordingly.
Why?

Could you explain what the purpose of this patch is?



Hi, sorry for the late reply. I haven't checked out the site for awhile.
1. render right then left was just an order of rendering to the buffers, back_right then back_left. But it changeable.
2. The stereo separation modify the projection matrix to create the asymmetric frustum, the stereo convergence modify the model view matrix it converge the two view at infinitive, that is why I've changed the name for the meaning of it. You can zero one of the two cvar to see the effect, if r_stereo_convergence=0 and r_stereo_separation=some_value then all things will be inside the monitor, if convergence have value and separation=0 then the stereo effect will be the original quake stereo effect, the toe-in method.
3. Explained above, asymmetric frustum stereo must modify the projection matrix not just the model view matrix. The reason for two separate cvar was intended for player because everyone have their own comfort settings. But if you prefer you could use one cvar for both projection matrix and model view matrix.
zuizme
Newbie
 
Posts: 5
Joined: Sun Jun 29, 2008 3:45 pm

Postby LordHavoc » Fri Aug 22, 2008 1:52 am

zuizme wrote:3. Explained above, asymmetric frustum stereo must modify the projection matrix not just the model view matrix. The reason for two separate cvar was intended for player because everyone have their own comfort settings. But if you prefer you could use one cvar for both projection matrix and model view matrix.


The r_stereo_separation cvar (and indeed, stereo rendering itself) did not exist in Quake, they are my additions, there is no reason to preserve the cvar.

However I still do not understand why you are modifying the projection matrix.
LordHavoc
Site Admin
 
Posts: 191
Joined: Wed Mar 29, 2006 7:39 am
Location: western Oregon, USA

Postby zuizme » Sat Aug 23, 2008 4:58 pm

LordHavoc wrote:
zuizme wrote:3. Explained above, asymmetric frustum stereo must modify the projection matrix not just the model view matrix. The reason for two separate cvar was intended for player because everyone have their own comfort settings. But if you prefer you could use one cvar for both projection matrix and model view matrix.


The r_stereo_separation cvar (and indeed, stereo rendering itself) did not exist in Quake, they are my additions, there is no reason to preserve the cvar.

However I still do not understand why you are modifying the projection matrix.


Well, I've actually been following this method by Paul Bourk
http://local.wasp.uwa.edu.au/~pbourke/p ... reorender/

This method calculate the asymmetric frustum then use the glFrustum to create the stereo projection matrix. In case of the matrix array the modification is the same as glFrustum.
zuizme
Newbie
 
Posts: 5
Joined: Sun Jun 29, 2008 3:45 pm


Return to Nexuiz - Development

Who is online

Users browsing this forum: No registered users and 1 guest

cron