Skip to main content
GameDev.net gamedev.net
🔒 Locked

Complecated mouse problem

Started by Rizo Aug 30, 2003 at 1:07 PM 5 replies 550+ views
Original Post
Rizo
Rizo
I''m creating an opengl and mfc application. What I need for my application is to allow the user to click in the opengl window. If I have the co-ordinates x,y of where they clicked how can I translate these to opengl x,y co-ordinates of where they clicked. Thanks in advance for any advice anyone can give.
mictian
mictian
well if you are in ortho mode you should just need to scale the (x,y) based on your resolution i think, but if you are in 3D you need to research "picking."

Basically cast a ray that goes through the camera position, and through the cursor position, and see what intersects it.

Sorry if that was totally irrelevant
¿We Create World?
Rizo
Rizo
thanks for pointing me in the right direction theres nothing about raycasting in the link you gave. If there is anyone else out there that can provide further information it will be appreciated.
iNsAn1tY
iNsAn1tY
"Picking" using the OpenGL selection buffer is next to useless. Raycasting is the way to go. Using gluUnProject, you can transform your window coords (x, y) into object coords (x, y, z). If you pass 0 and 1 into the z argument of gluUnProject, you'll get object coords on the near and far clipping planes respectively. There you have your ray.

Using the dot product, you can check to see if the planes of any of your polygons are intersected by the ray. Then you can check to see if the polygons themselves are intersected. Then you take your list of intersected polygons, and see which is closest. There's a decent tutorial over at www.gametutorials.com which deals with a line intersecting a polygon. This is the tutorial you need. Happy hunting...



Coding Stuff ->  [ iNsAn1tY Games | DarkVertex | How To Do CSG | Direct3D Vs. OpenGL | Google ]
Fun Stuff    ->  [ Evil T-Shirts | Stick-Based Comedy | You're Already Here | The Best Film Reviews ]


[edited by - iNsAn1tY on August 31, 2003 6:30:59 AM]
My opinion is a recombination and regurgitation of the opinions of those around me. I bring nothing new to the table, and as such, can be safely ignored.[ Useful things - Firefox | GLee | Boost | DevIL ]
Rizo
Rizo
Thanks iNsAn1tY for the information. When I click the mouse I want it to store the point of where I clicked in the 3d model so I can draw a line from the point to the origin of the model.

i.e the start of the line is the point where I clicked and the end is the origin.

The problem now is that the line does pass through the point I clicked but it is much longer than what it should be why is this happening?

I''m including the code any help from anyone is appreciated.

// OpenglTop.cpp : implementation file
//

#include "stdafx.h"
#include "Riggor.h"
#include "OpenglTop.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// COpenglTop

IMPLEMENT_DYNCREATE(COpenglTop, COpenglOrth)

COpenglTop::COpenglTop()
{
ChamPosition.x = 0.0;
ChamPosition.y = 0.0;
ChamPosition.z = 5.0;
LookAt.x = 0.0;
LookAt.y = 0.0;
LookAt.z = 0.0;

clicked = FALSE;
fptr = fopen( "test.txt", "w+" );
}

COpenglTop::~COpenglTop()
{
}


BEGIN_MESSAGE_MAP(COpenglTop, CView)
//{{AFX_MSG_MAP(COpenglTop)
ON_WM_CREATE()
ON_WM_SIZE()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// COpenglTop drawing

void COpenglTop::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();

SetContext();
RenderScene();
SwapGLBuffers();
}

void COpenglTop::RenderScene()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glLoadIdentity();
gluLookAt( ChamPosition.x, ChamPosition.y, ChamPosition.z,
LookAt.x, LookAt.y, LookAt.z, 0.0, 1.0, 0.0 );

DrawGrid();

glFlush();
}

void COpenglTop::DrawGrid()
{
float i;

CRiggorDoc* pDoc = CRiggorView::GetDocument();

glColor3f(0.0,0.0,1.0);

glBegin(GL_LINE_LOOP);
glVertex3f( pDoc->GridStart.x, pDoc->GridStart.y, pDoc->GridStart.z );
glVertex3f( pDoc->GridStart.x, pDoc->GridEnd.y, pDoc->GridStart.z );
glVertex3f( pDoc->GridEnd.x, pDoc->GridEnd.y, pDoc->GridStart.z );
glVertex3f( pDoc->GridEnd.x, pDoc->GridStart.y, pDoc->GridStart.z );
glEnd();

glColor3f(1.0,1.0,1.0);
glBegin(GL_LINES);
for( i = pDoc->GridStart.x ; i < pDoc->GridEnd.x; i+=1 )
{
glVertex3f( i, pDoc->GridStart.y, pDoc->GridStart.z );
glVertex3f( i, pDoc->GridEnd.y, pDoc->GridStart.z );
}
for( i = pDoc->GridStart.y ; i < pDoc->GridEnd.y; i+=1 )
{
glVertex3f( pDoc->GridStart.x, i, pDoc->GridStart.z );
glVertex3f( pDoc->GridEnd.x, i, pDoc->GridStart.z );
}
glColor3f(0.0,1.0,0.0);
if(clicked == TRUE)
{
glVertex3f( wx , wy, pDoc->GridStart.z );
glVertex3f( 0, 0, pDoc->GridStart.z );
}
glEnd();


}
/////////////////////////////////////////////////////////////////////////////
// COpenglTop diagnostics

#ifdef _DEBUG
void COpenglTop::AssertValid() const
{
CView::AssertValid();
}

void COpenglTop::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// COpenglTop message handlers

int COpenglTop::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (COpenglOrth::OnCreate(lpCreateStruct) == -1)
return -1;

return 0;
}

void COpenglTop::OnSize(UINT nType, int cx, int cy)
{
COpenglOrth::OnSize(nType, cx, cy);

}

void COpenglTop::OnMouseMove(UINT nFlags, CPoint point)
{
BOOL RedrawWindow = FALSE;

if( nFlags & MK_LBUTTON )
{
if( iMousePrevY != -1 )
{
if(iMousePrevY ChamPosition.y -= 1;
LookAt.y -= 1;
RedrawWindow = TRUE;
}
else if(iMousePrevY>point.y){
ChamPosition.y += 1;
LookAt.y += 1;
RedrawWindow = TRUE;
}
}

if( iMousePrevX != -1 )
{
if(iMousePrevX ChamPosition.x -= 1;
LookAt.x -= 1;
RedrawWindow = TRUE;
}
if(iMousePrevX>point.x){
ChamPosition.x += 1;
LookAt.x += 1;
RedrawWindow = TRUE;
}

}


iMousePrevX = point.x;
iMousePrevY = point.y;
}
else if( nFlags & MK_RBUTTON )
{

if( iMousePrevY != -1 )
{
if(iMousePrevY ChamPosition.z -= 1;
LookAt.z -=1;
RedrawWindow = TRUE;
}
else if(iMousePrevY>point.y){
ChamPosition.z += 1;
LookAt.z +=1;
RedrawWindow = TRUE;
}
}

iMousePrevX = point.x;
iMousePrevY = point.y;
}

else
{
iMousePrevX = -1;
iMousePrevY = -1;
}

if( RedrawWindow == TRUE )
OnDraw(NULL);

CView::OnMouseMove(nFlags, point);
}

void COpenglTop::OnLButtonDown(UINT nFlags, CPoint point)
{



GLint viewport[4];
GLdouble mvmatrix[16], projmatrix[16];
GLint realy;

glGetIntegerv( GL_VIEWPORT, viewport );
glGetDoublev( GL_MODELVIEW_MATRIX, mvmatrix );
glGetDoublev( GL_PROJECTION_MATRIX, projmatrix );

realy = viewport[3] - (GLint) point.y - 1;


gluUnProject( ( GLdouble)point.x, (GLdouble)realy, 1.0 ,
mvmatrix, projmatrix, viewport, &wx, &wy, &wz);

clicked = TRUE;


fprintf(fptr, "x: %f " , wx );
fprintf(fptr, "y: %f " , wy );
fprintf(fptr, "z: %f\n" , wz );

CView::OnLButtonDown(nFlags, point);
OnDraw(NULL);
}
iNsAn1tY
iNsAn1tY
I'm not exactly sure what you're aiming for, but I think I see. You want the user to click, and their click creates a line from the viewport to the polygon of the model where the click hit? If that's the case, then you need to do everything I said in my previous post (testing polygons, etc.), but then you need to take the distance information of the polygon which was hit, and use it to calculate the exact point on the ray where it intersects the polygon.

Basically, you'll have a scalar value, say t = 0.678, which is the distance from the start of the ray to the polygon intersection (where t = 0.0 is the ray start, and t = 1.0 is the ray end). You can get the intersection point (x, y, z) by using the following formula:
NewPoint.x = RayStart.x + (t * RayDirection.x);
NewPoint.y = RayStart.y + (t * RayDirection.y);
NewPoint.z = RayStart.z + (t * RayDirection.z);
Then, just make the line (RayStart -> NewPoint). If that's what you're trying to do, all well and good. If it isn't, post back.

EDIT: In the code you've posted, you're getting the "end" of the ray (sending 1.0f as the z value to gluUnProject), but you're not getting the "start" of the ray. Actually, re-reading your post, it seems like you want the line to start at the viewport, and go to the origin. This is simple. You just get the "start" of the ray (send a z value of 0.0f instead of 1.0f to gluUnProject), and then draw a line from the point returned to (0, 0, 0). Anyway, I'll leave that stuff above just in case you need it...



Coding Stuff ->  [ iNsAn1tY Games | DarkVertex | How To Do CSG | Direct3D Vs. OpenGL | Google ]
Fun Stuff    ->  [ Evil T-Shirts | Stick-Based Comedy | You're Already Here | The Best Film Reviews ]


[edited by - iNsAn1tY on September 1, 2003 5:44:22 AM]
My opinion is a recombination and regurgitation of the opinions of those around me. I bring nothing new to the table, and as such, can be safely ignored.[ Useful things - Firefox | GLee | Boost | DevIL ]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.