Click here to Skip to main content
15,892,927 members
Articles / Multimedia / OpenGL

Interactive Techniques in Three-dimensional Scenes (Part 1): Moving 3D Objects with the Mouse using OpenGL 2.1

Rate me:
Please Sign up or sign in to vote.
4.97/5 (80 votes)
22 Apr 2009CPOL38 min read 319.1K   25.6K   225  
Moving 3D objects with the mouse using OpenGL.
//  Copyright (C) 2008 Steven Katic 

#pragma once

using namespace System;
using namespace System::Windows::Forms;
using namespace FileViewerTypes;

// something small to avoid division overflow but the granularity is to small to be detected in the OpenGL modelview matrix elements
//#define EPSILON 1.0e-8 
#define EPSILON 2.5e-8 // something still very small to avoid division overflow but now also big enough to detect OpenGL modelview matrix elements
#define ZERO EPSILON

//===========================================================================================
//    Plane defined by a point and a normal
//    The normal and point are expressed in non-opengl 3D cartesian co-ordinates.
//    where the Z axis in vertical. In OpenGL the Y axis is vertical. 
//===========================================================================================
public ref class Plane
{
public:

	Vector3^ Normal;
	Vector3^ Position;
	DWORD axesAlignment;
	
	Plane(void)
	{
		Normal = Vector3::Zero();
		Position = Vector3::Zero();		
	}

	Plane(Vector3^ norm,Vector3^ pos, DWORD axes)
	{
		Normal = gcnew Vector3(norm->X,norm->Y,norm->Z);
		Position = gcnew Vector3(pos->X,pos->Y,pos->Z);
		AxesAlignment = axes;
	}

	void DrawNormal()
	{
		glDisable(GL_LIGHTING);
		glEnable(GL_LINE_SMOOTH);
		glDisable( GL_TEXTURE_2D );
		glLineWidth(2.0);		
		glBegin(GL_LINES);
		glColor3f(1.0f,1.0f,0.0f);
		glVertex3f(Position->X,Position->Z,Position->Y);
		glVertex3f(Normal->X*10+Position->X,Normal->Z*10+Position->Z,Normal->Y*10+Position->Y);
		glEnd();
		glEnable(GL_LIGHTING);
		glDisable(GL_LINE_SMOOTH);
		glEnable( GL_TEXTURE_2D );
	}

	void Draw()
	{
		
		glDisable(GL_LIGHTING);
		glEnable(GL_LINE_SMOOTH);
		glDisable( GL_TEXTURE_2D );
		glEnable(GL_COLOR_MATERIAL);
		glLineWidth(1.0);
		//glColor3f(1.0f,0.0f,0.0f);

		float size = 5.0f;
		// xy plane default
		float x = Position->X;
		float y = Position->Z;
		float z = Position->Y;

		glPushMatrix();
			if(axesAlignment == XYTRANS)
			{
				x = Position->X;
				y = Position->Z;
				z = Position->Y;			
			}
			else if(axesAlignment == ZXTRANS)
			{
				glRotatef(90.0f,1.0f,0.0f,0.0f);
				x = Position->X;
				y = Position->Y;
				z = -Position->Z;			
			}
			else if(axesAlignment == YZTRANS)
			{
				glRotatef(-90.0f,0.0f,0.0f,1.0f);
				x = -Position->Z;
				y = Position->X;
				z = Position->Y;
			}
			
			glEnable(GL_BLEND);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			glColor4f(1.0f,0.0f,1.0f,0.2f);
			glBegin(GL_QUADS);				
				glVertex3f(x-size,y,z-size);
				glVertex3f(x-size,y,z+size);				
				glVertex3f(x+size,y,z+size);
				glVertex3f(x+size,y,z-size);				
			glEnd();
			glDisable(GL_BLEND);
			
			glColor3f(1.0f,0.0f,0.0f);
			glBegin(GL_LINES);				
				glVertex3f(x-size,y,z-size);
				glVertex3f(x-size,y,z+size);
				glVertex3f(x+size,y,z-size);
				glVertex3f(x+size,y,z+size);
				glVertex3f(x-size,y,z-size);
				glVertex3f(x+size,y,z-size);
				glVertex3f(x-size,y,z+size);
				glVertex3f(x+size,y,z+size);				
			glEnd();
			
			
		glPopMatrix();

		glEnable(GL_LIGHTING);
		glDisable(GL_LINE_SMOOTH);
		glEnable( GL_TEXTURE_2D );
		
	}

	property DWORD AxesAlignment
	{
		void set(DWORD value)
		{ 
			axesAlignment = value;			
		}
		DWORD get(){ return axesAlignment; }
	}	


};

//===========================================================================================
//	Ray defined by 2 points (can we call it a segment?)
//
//	The 2 points p0 and p1 are expressed in non-opengl cartesian co-ordinates.
//	where the Z axis in vertical. In opengl the screen and the Y axis is vertical.
//===========================================================================================

public ref class Ray
{

public:
	Vector3^ p0;
	Vector3^ p1;

	Ray(void)
	{
		p0 = Vector3::Zero();
		p1 = Vector3::Zero();
	}

	Ray(Vector3^ P0,Vector3^ P1)
	{
		p0 = Vector3::Zero();
		p1 = Vector3::Zero();

		p0->X = P0->X;
		p0->Y = P0->Y;
		p0->Z = P0->Z;
		p1->X = P1->X;
		p1->Y = P1->Y;
		p1->Z = P1->Z;
		
	}

	Ray(int x2D, int y2D)
	{
		p0 = Vector3::Zero();
		p1 = Vector3::Zero();
		Generate3DRay(x2D, y2D);		
	}

	void Generate3DRay(int x2D, int y2D)
	{
		if(p0 == nullptr)
			p0 = Vector3::Zero();
		if(p1 == nullptr)
			p1 = Vector3::Zero();
	
		int x =x2D;
		int y =y2D;	
		GLint viewport[4];	
		GLdouble modelview[16];
		GLdouble projection[16];
		GLdouble winX, winY; 
		GLdouble winZ0 = 0.0f; GLdouble winZ1 = 1.0f;
		GLdouble posX0, posY0, posZ0;
		GLdouble posX1, posY1, posZ1;
		
		glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
		glGetDoublev(GL_PROJECTION_MATRIX, projection);
		glGetIntegerv(GL_VIEWPORT, viewport);		

		winX = (GLdouble)x;
		winY = (GLdouble)viewport[3] - (GLdouble)y;

		glReadBuffer( GL_BACK );
		
		gluUnProject( winX, winY, winZ0, modelview, projection, viewport, &posX0, &posY0, &posZ0);
		gluUnProject( winX, winY, winZ1, modelview, projection, viewport, &posX1, &posY1, &posZ1);
		// flip opengl co-ordinates to flight simulator co-ordinates
		p0->X = (float)posX0;
		p0->Y = (float)posZ0;
		p0->Z = (float)posY0;
		//
		p1->X = (float)posX1;
		p1->Y = (float)posZ1;
		p1->Z = (float)posY1;
	}

	//=======================================================
	// Intersects(): intersect a segment and a plane
	//    Input:  p = a plane 
	//    Output: I = the intersection point (when it exists)
	//    Return: 0 = disjoint (no intersection)
	//            1 = intersection in the unique point I
	//            2 = the segment lies in the plane
	//
	// Adapted from:
	// http://www.softsurfer.com/Archive/algorithm_0104/algorithm_0104B.htm#Line-Plane%20Intersection
	//
	// Preconditions:
	//
	//		- the plane is in flight simulator co-ordinate system form, where the Z axis in vertical
	//		  (whereas in OpenGL the Y axis is vertical ).
	//
	//=======================================================
	int Intersects(Plane^ p, Vector3^ I)
	{
		Vector3^ intersectPoint;

		Vector3^ u = p1 - p0;
		Vector3^ w = p0 - p->Position;
		
		float     D = p->Normal->Dot(u);
		float     N = -p->Normal->Dot(w);

		if (Math::Abs(D) < ZERO)			// segment is parallel to plane
		{          
			if (N == 0)                     // segment lies in plane
				return 2;
			else
				return 0;                   // no intersection
		}

		float s = N / D;
		if (s < 0 || s > 1)
			return 0;                       // no intersection

		intersectPoint = p0 + u*s;         // compute segment intersect point

		I->X  = intersectPoint->X;
		I->Y  = intersectPoint->Y;
		I->Z  = intersectPoint->Z;
		
		return 1;
	}

};

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions