Results 1 to 3 of 3

Thread: Stereoscopic - Cannot perceive depth difference

  1. #1
    Junior Member Newbie
    Join Date
    Sep 2014
    Posts
    2

    Stereoscopic - Cannot perceive depth difference

    Hi everyone,

    I am using OpenGL to build some basic psychological experiments, and many of these are done using stereoscopic displays. In this case, I am drawing 3D arrows on the screen at various different times, and having users respond to the direction of them.

    I am having a problem with being unable to perceive differences in depth plane of objects in relationship to each other. The objects do appear '3D' and 'pop out', but I cannot perceive depth differences. I am using an orthographic projection matrix (there seems to be a difference in depth on the perspective projection, but this is likely due solely the additional depth cue of the perspective...) I am primarily using GLUT.

    There's enough code where it isn't practical to share all of the code right now, but below are a few of the areas I think may be related to the issue. However, if anyone wants to dive into the full set of code, I can share that as well. If any additional information would be helpful, or other snippets, please let me know.

    Please feel free to ask anything that you think will help you understand what I am doing, and I'll provide whatever I can to help.

    (Disclaimer: I realize that much of my code is inefficient and not the neatest)

    Here is the Display() function, with some omissions to simplify.

    Code :
    	xyz eyePosition;
    	GLdouble left = 0.1;
    	GLdouble right = 0.1;
    	GLdouble Far = 100000;
    	GLdouble ratio = camera.getRatio();
    	GLdouble radians = DTOR * camera.getAperture() / 2;
    	GLdouble Near = 0.0001;
    	GLdouble wd2 = Near * tan(radians);
    	GLdouble ndfl = Near / camera.getFocalLength();
    	GLdouble top = wd2;
    	GLdouble bottom = -wd2;
     
    	glDrawBuffer(GL_BACK_LEFT);
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    	glDrawBuffer(GL_BACK_RIGHT);
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     
    		CROSSPRODUCT(camera.viewDirection, camera.viewUpDirection, eyePosition);
    		Normalize(&eyePosition);
    		eyePosition.x *= camera.getEyeSeparation() / 1.5;
    		eyePosition.y *= camera.getEyeSeparation() / 1.5;
    		eyePosition.z *= camera.getEyeSeparation() / 1.5;
     
    		glMatrixMode(GL_PROJECTION);
    		glLoadIdentity();
    		left = -ratio * wd2 - 0.5 * camera.getEyeSeparation() * ndfl;
    		right = ratio * wd2 - 0.5 * camera.getEyeSeparation() * ndfl;
    		top = wd2;
    		bottom = -wd2;
     
    		if (experiment.condition == 0)     //Perspective
    		{
    			glFrustum(left, right, bottom, top, Near, Far);
    		}
    		else if (experiment.condition == 1)     //Orthographic
    		{
    			glOrtho(left, right, bottom, top, Near, Far);
    		}
     
    		glMatrixMode(GL_MODELVIEW);
    		glDrawBuffer(GL_BACK_RIGHT);
    		glLoadIdentity();
    		gluLookAt(camera.viewPosition.x + eyePosition.x, camera.viewPosition.y + eyePosition.y, camera.viewPosition.z + eyePosition.z,
    			camera.viewPosition.x + eyePosition.x + camera.viewDirection.x,
    			camera.viewPosition.y + eyePosition.y + camera.viewDirection.y,
    			camera.viewPosition.z + eyePosition.z + camera.viewDirection.z,
    			camera.viewUpDirection.x, camera.viewUpDirection.y, camera.viewUpDirection.z);
    		Lighting();
    		DrawStimuli();     //This function is where I actually draw the arrows.  I'll add this separately below
     
    		//This is all repeated for the other eye, in the positive direction

    And here is the DrawStimuli() function
    Code :
    	GLfloat specular[4] = { 1.0, 1.0, 1.0, 1.0 };
    	GLfloat shiny[1] = { 5.0 };
     
    	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
    	glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shiny);
     
    //I have a class called 'arrow' that contains the x,y,z coordinates for a cube (stem of the arrow) and four triangles (head of the arrow).  These values are all initialized here, but omitted from this post
     
    //The experiment class contains most of the world coordinates, etc.
    		experiment.xWidth = 0.1f/10000.0f;
    		experiment.yHeight = 0.0f;
    		experiment.trial.DistZDepth = 0.0f;
    		experiment.trial.TargetZDepth = 0.0f;
    		experiment.zInitialDepth = -6.0f;		//This is initial, starting depth
    		experiment.planeDistance = 5.0f;
     
    //There are 9 different cases here, depending on which depth plane for dist and target, but I'm only showing 2 for simplicity
    switch (experiment.orderVector[experiment.trial.trialNumber] % 9)
    		{
    		case 0:
    			experiment.trial.DistZDepth = -experiment.planeDistance + experiment.zInitialDepth;
    			experiment.trial.distPlane = 1;
    			experiment.trial.targetPlane = 1;
    			experiment.trial.TargetZDepth = -experiment.planeDistance + experiment.zInitialDepth;
    			break;
    		case 1:
    			experiment.trial.DistZDepth = -experiment.planeDistance + experiment.zInitialDepth;
    			experiment.trial.distPlane = 1;
    			experiment.trial.targetPlane = 2;
    			experiment.trial.TargetZDepth = 0.1f + experiment.zInitialDepth;
    			break;
    		}
     
    			glPushMatrix();
    			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);		//Clear screen and depth buffers
     
    			//Build distractor arrows
    			if (experiment.trial.distDirection == NEUTRAL)
    			{
    				//Build d1 arrow (far left)
    				glLoadIdentity();										//Reset the view to the center of the screen
    				glTranslatef(-(experiment.xWidth*0.5f), experiment.yHeight, experiment.trial.DistZDepth);
    				buildArrow(neutralDistractor);
    				//Build d2 arrow (middle left)
    				glLoadIdentity();										//Reset the view to the center of the screen
    				glTranslatef(-(experiment.xWidth*0.25f), experiment.yHeight, experiment.trial.DistZDepth);
    				buildArrow(neutralDistractor);
    				//Build d3 arrow (middle right)
    				glLoadIdentity();										//Reset the view to the center of the screen
    				glTranslatef((experiment.xWidth*0.25f), experiment.yHeight, experiment.trial.DistZDepth);
    				buildArrow(neutralDistractor);
    				//Build d4 arrow (far right)
    				glLoadIdentity();										//Reset the view to the center of the screen
    				glTranslatef((experiment.xWidth*0.5f), experiment.yHeight, experiment.trial.DistZDepth);
    				buildArrow(neutralDistractor);
    			}
    //There are two other directions (left and right) that repeat this code but build different arrows in the buildArrow(arrow) function.  Omitted for simplicity.
    			//Update type to Target
    			rightArrow.type = TARGET;
    			leftArrow.type = TARGET;
     
    			//Build target arrow
    			if (experiment.trial.targetDirection == LEFT)
    			{
    				glLoadIdentity();										//Reset the view to the center of the screen
    				glTranslatef(0.0f, experiment.yHeight, experiment.trial.TargetZDepth);
    				buildArrow(leftArrow);
    			}
    			else if (experiment.trial.targetDirection == RIGHT)
    			{
    				glLoadIdentity();										//Reset the view to the center of the screen
    				glTranslatef(0.0f, experiment.yHeight, experiment.trial.TargetZDepth);
    				buildArrow(rightArrow);
    			}
     
    			glPopMatrix();
    Finally, here is the buildArrow function. It's messy and possibly unclear without seeing the entire arrow class... but here it is!
    Code :
    GLvoid buildArrow(Arrow a)
    {
    	xyz n;
     
    	n = CalculateNormal(a.t1.p1, a.t1.p2, a.t1.p3);
    	glBegin(GL_TRIANGLES);		//Base
    	glNormal3f(n.x, n.y, n.z);
    	glVertex3f(a.t1.p1.x, a.t1.p1.y, a.t1.p1.z);
    	glVertex3f(a.t1.p2.x, a.t1.p2.y, a.t1.p2.z);
    	glVertex3f(a.t1.p3.x, a.t1.p3.y, a.t1.p3.z);
    	glEnd();
    	n = CalculateNormal(a.t2.p1, a.t2.p2, a.t2.p3);
    	glBegin(GL_TRIANGLES);		//Top
    	glNormal3f(n.x, n.y, n.z);
    	glVertex3f(a.t2.p1.x, a.t2.p1.y, a.t2.p1.z);
    	glVertex3f(a.t2.p2.x, a.t2.p2.y, a.t2.p2.z);
    	glVertex3f(a.t2.p3.x, a.t2.p3.y, a.t2.p3.z);
    	glEnd();
    	n = CalculateNormal(a.t3.p1, a.t3.p2, a.t3.p3);
    	glBegin(GL_TRIANGLES);		//Bottom
    	glNormal3f(n.x, n.y, n.z);
    	glVertex3f(a.t3.p1.x, a.t3.p1.y, a.t3.p1.z);
    	glVertex3f(a.t3.p2.x, a.t3.p2.y, a.t3.p2.z);
    	glVertex3f(a.t3.p3.x, a.t3.p3.y, a.t3.p3.z);
    	glEnd();
    	n = CalculateNormal(a.t4.p1, a.t4.p2, a.t4.p3);
    	glBegin(GL_TRIANGLES);		//Back
    	glNormal3f(n.x, n.y, n.z);
    	glVertex3f(a.t4.p1.x, a.t4.p1.y, a.t4.p1.z);
    	glVertex3f(a.t4.p2.x, a.t4.p2.y, a.t4.p2.z);
    	glVertex3f(a.t4.p3.x, a.t4.p3.y, a.t4.p3.z);
    	glEnd();
     
    	//In this iteration, we are only drawing the quads if it is a distractor and the type is neutral
    	if (a.type == DISTRACTOR && experiment.trial.distDirection == NEUTRAL)
    	{
    		//glColor3f(0.2f, 0.2f, 0.2f);
    		n = CalculateNormal(a.s1.p1, a.s1.p2, a.s1.p3);
    		glBegin(GL_QUADS);		//Top
    		glNormal3f(n.x, n.y, n.z);
    		glVertex3f(a.s1.p1.x, a.s1.p1.y, a.s1.p1.z);
    		glVertex3f(a.s1.p2.x, a.s1.p2.y, a.s1.p2.z);
    		glVertex3f(a.s1.p3.x, a.s1.p3.y, a.s1.p3.z);
    		glVertex3f(a.s1.p4.x, a.s1.p4.y, a.s1.p4.z);
    		glEnd();
    		n = CalculateNormal(a.s2.p1, a.s2.p2, a.s2.p3);
    		glBegin(GL_QUADS);		//Back
    		glNormal3f(n.x, n.y, n.z);
    		//glColor3f(0.0f, 0.0f, 0.0f);
    		glVertex3f(a.s2.p1.x, a.s2.p1.y, a.s2.p1.z);
    		glVertex3f(a.s2.p2.x, a.s2.p2.y, a.s2.p2.z);
    		glVertex3f(a.s2.p3.x, a.s2.p3.y, a.s2.p3.z);
    		glVertex3f(a.s2.p4.x, a.s2.p4.y, a.s2.p4.z);
    		glEnd();
    		n = CalculateNormal(a.s3.p1, a.s3.p2, a.s3.p3);
    		glBegin(GL_QUADS);		//Bottom
    		glNormal3f(n.x, n.y, n.z);
    		glVertex3f(a.s3.p1.x, a.s3.p1.y, a.s3.p1.z);
    		glVertex3f(a.s3.p2.x, a.s3.p2.y, a.s3.p2.z);
    		glVertex3f(a.s3.p3.x, a.s3.p3.y, a.s3.p3.z);
    		glVertex3f(a.s3.p4.x, a.s3.p4.y, a.s3.p4.z);
    		glEnd();
    		n = CalculateNormal(a.s4.p1, a.s4.p2, a.s4.p3);
    		glBegin(GL_QUADS);		//Front
    		glNormal3f(n.x, n.y, n.z);
    		glVertex3f(a.s4.p1.x, a.s4.p1.y, a.s4.p1.z);
    		glVertex3f(a.s4.p2.x, a.s4.p2.y, a.s4.p2.z);
    		glVertex3f(a.s4.p3.x, a.s4.p3.y, a.s4.p3.z);
    		glVertex3f(a.s4.p4.x, a.s4.p4.y, a.s4.p4.z);
    		glEnd();
    		n = CalculateNormal(a.s5.p1, a.s5.p2, a.s5.p3);
    		glBegin(GL_QUADS);		//Left
    		glNormal3f(n.x, n.y, n.z);
    		glVertex3f(a.s5.p1.x, a.s5.p1.y, a.s5.p1.z);
    		glVertex3f(a.s5.p2.x, a.s5.p2.y, a.s5.p2.z);
    		glVertex3f(a.s5.p3.x, a.s5.p3.y, a.s5.p3.z);
    		glVertex3f(a.s5.p4.x, a.s5.p4.y, a.s5.p4.z);
    		glEnd();
    		n = CalculateNormal(a.s6.p1, a.s6.p2, a.s6.p3);
    		glBegin(GL_QUADS);		//Right
    		glNormal3f(n.x, n.y, n.z);
    		glVertex3f(a.s6.p1.x, a.s6.p1.y, a.s6.p1.z);
    		glVertex3f(a.s6.p2.x, a.s6.p2.y, a.s6.p2.z);
    		glVertex3f(a.s6.p3.x, a.s6.p3.y, a.s6.p3.z);
    		glVertex3f(a.s6.p4.x, a.s6.p4.y, a.s6.p4.z);
    		glEnd();
    	}
    }

    EDIT: Forgot to include some important stuff.
    Video Card: NVidia Quadro K600
    Monitor: Acer GD235HZ
    OS: Windows 7
    3D Glasses: Nvidia 3D Vision

  2. #2
    Newbie Frequent Contributor
    Join Date
    Mar 2016
    Posts
    896
    I am using an orthographic projection matrix
    Your code calls glFrustum to set up the projection matrix, that won't give you an orthographic projection? Usually one shifts the eye points along the camera x axis to the left and right and constructs the view frusta such that there is a plane (parallel to the camera xy plane) where they coincide - in particular they are not symmetric frusta, but the left one is slightly skewed to the right and the other way round for the right one.

    Other than that, since you are doing a psychological experiment I guess you already know that some aspects of human vision can not be explained entirely by optical geometry. If you present two abstract objects (where the viewer has no knowledge about their absolute or relative sizes) without a surrounding environment it becomes very hard to distinguish two same-size objects at different depths from two different-size objects at the same depth.

  3. #3
    Junior Member Newbie
    Join Date
    Sep 2014
    Posts
    2
    Quote Originally Posted by carsten neumann View Post
    Your code calls glFrustum to set up the projection matrix, that won't give you an orthographic projection?
    There's actually an if statement that uses glFrustum for perspective and glOrtho for orthographic... that's part of what I omitted from the post. I'll edit the code to show both, for those who go look at it in the future. Nice catch here.

    Quote Originally Posted by carsten neumann View Post
    Other than that, since you are doing a psychological experiment I guess you already know that some aspects of human vision can not be explained entirely by optical geometry. If you present two abstract objects (where the viewer has no knowledge about their absolute or relative sizes) without a surrounding environment it becomes very hard to distinguish two same-size objects at different depths from two different-size objects at the same depth.
    Yeah, this is a limitation where I was hoping that exaggerated differences on the depth plane would make this at least subtly different. In the real world, you can perceive two different objects at different differences as the same size (assuming that the larger one is behind, of course) and still tell the difference in depth, albeit with more uncertainty. I'm hoping to find a way around this. While I imagine that you may well be right, my goal is to find a way to give this perception without including additional cues.

Similar Threads

  1. 3D Stereoscopic with OpenGL ES
    By hasan in forum OpenGL ES
    Replies: 1
    Last Post: 02-21-2011, 10:32 AM
  2. CUDA CANNOT perceive changing VBO with glMapBuffer
    By Vulcann in forum OpenGL: Advanced Coding
    Replies: 4
    Last Post: 01-24-2011, 06:05 AM
  3. Windows 7 stereoscopic
    By goatrance in forum OpenGL: User Software
    Replies: 4
    Last Post: 02-09-2009, 10:05 AM
  4. StereoScopic
    By SeeDAreW in forum OpenGL: Basic Coding
    Replies: 28
    Last Post: 03-14-2002, 04:29 AM
  5. Stereoscopic view...
    By Neczka in forum OpenGL: User Software
    Replies: 3
    Last Post: 01-01-2002, 04:44 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Proudly hosted by Digital Ocean