Getting a 2D Polygon from 3D face

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
asparagusx
Posts: 81
Joined: Thu Oct 16, 2008 6:50 am

Getting a 2D Polygon from 3D face

Post by asparagusx »

Hello

I am completely stuck. I need to obtain a 2D polygon from a face displayed in a 3D mesh.

Here is a picture of what I need. The red 'polygon' is what I need in 2D e.g. looking from the camera from position, I need the coordinates of the red 3D face, but as 2D points.

I hope this makes sense - I am completely stuck. I have tried using viewing, projection and world matrices with no luck to transform the 3D points.

Image

Thanks

Asp
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Post by Lonesome Ducky »

http://irrlicht.sourceforge.net/docu/cl ... 70c0b2393d
This is a function to convert from a 3d point to a 2d. An example would be:

Code: Select all

smgr->getSceneCollisionManager->getScreenCoordinatesFrom3DPosition(pos)
asparagusx
Posts: 81
Joined: Thu Oct 16, 2008 6:50 am

Post by asparagusx »

Ducky

That was the first routine I looked at, but it still did not give me the correct results. I will look at it again and see what I can come up with.

Thanks

Asp
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

That is the function you need. You may need to transform the vertex positions into the world coordinate system before using that function, but that is what you want.

Travis
asparagusx
Posts: 81
Joined: Thu Oct 16, 2008 6:50 am

Post by asparagusx »

Travis

Could you clarify that please? I am now using that function, but I am still getting a 'skewed' view in 2D. I need exactly the same 'view' as I have in 3D, but converted to 2D polygons. I need to use this to do Hidden Line/Surface Removal.

Thanks

Asp
asparagusx
Posts: 81
Joined: Thu Oct 16, 2008 6:50 am

Post by asparagusx »

Vitek

Here is a picture of what I am now getting. The blue mesh on the right is the 3d model, with a face highlighted in red. On the lefthand side is a 2D view with the same face highlighted. You can see that it is 'squashed'. What I need is the view on the right, but converted to 2d. I have slightly modified my own version of getScreenCoordinatesFrom3DPosition, as I am trying to maintain the aspect ratios etc.

Image


Here is what I have at the moment :
(I2DPnt is equavalent to vector2df)



Code: Select all

I2DPnt IHLR::GetCoords(core::vector3df pos3d, ICameraSceneNode* camera)
	{
	ISceneManager *smgr = pCD->DwgSmgr;
	
	if (!smgr || !Device->driver)
		return I2DPnt(-1000,-1000);//core::position2d<s32>(-1000,-1000);

	if (!camera)
		camera = smgr->getActiveCamera();

	if (!camera)
		return I2DPnt(-1000,-1000);
		//return core::position2d<s32>(-1000,-1000);

	const core::rect<s32>& viewPort = Device->driver->getViewPort();
	core::dimension2d<s32> dim(viewPort.getWidth(), viewPort.getHeight());

	dim.Width /= 2;
	dim.Height /= 2;

	core::matrix4 trans = camera->getProjectionMatrix();
	trans *= camera->getViewMatrix();

	f32 transformedPos[4] = { pos3d.X, pos3d.Y, pos3d.Z, 1.0f };

	trans.multiplyWith1x4Matrix(transformedPos);

	if (transformedPos[3] < 0)
		//return core::position2d<s32>(-10000,-10000);
		return I2DPnt(-10000,-10000);
		
	I2DPnt p(transformedPos[0],transformedPos[1]);

	//return p;

	const f32 zDiv = transformedPos[3] == 0.0f ? 1.0f :
		core::reciprocal(transformedPos[3]);

	
	I2DPnt Screen(viewPort.getWidth(),viewPort.getHeight());
	
	
	p.set(Screen.x * (transformedPos[0] * zDiv),Screen.y * (transformedPos[1] * zDiv));
	//return core::position2d<s32>(
	//		core::round32(dim.Width * transformedPos[0] * zDiv) + dim.Width,
	//		dim.Height - core::round32(dim.Height * (transformedPos[1] * zDiv)));
	return p;
	}

The input to this routine is a position vector, directly retrieved from a SMeshBuffer.

Thanks

Asp
Geomaster
Posts: 71
Joined: Tue Oct 21, 2008 3:39 pm

Post by Geomaster »

Try using this (untested):

Code: Select all

I2DPnt IHLR::GetCoords(core::vector3df pos3d, ICameraSceneNode* camera)
   {
   ISceneManager *smgr = pCD->DwgSmgr;
   
   if (!smgr || !Device->driver)
      return I2DPnt(-1000,-1000);//core::position2d<s32>(-1000,-1000);

   if (!camera)
      camera = smgr->getActiveCamera();

   if (!camera)
      return I2DPnt(-1000,-1000);
      //return core::position2d<s32>(-1000,-1000);

   const core::rect<s32>& viewPort = Device->driver->getViewPort();
   core::dimension2d<s32> dim(viewPort.getWidth(), viewPort.getHeight());

   dim.Width /= 2;
   dim.Height /= 2;

   core::matrix4 trans = camera->getProjectionMatrix();
   trans *= camera->getViewMatrix();
   trans *= driver->getTransofrm(ETS_WORLD); // <- added

   f32 transformedPos[4] = { pos3d.X, pos3d.Y, pos3d.Z, 1.0f };

   trans.multiplyWith1x4Matrix(transformedPos);

   if (transformedPos[3] < 0)
      //return core::position2d<s32>(-10000,-10000);
      return I2DPnt(-10000,-10000);
      
   I2DPnt p(transformedPos[0],transformedPos[1]);

   //return p;

   const f32 zDiv = transformedPos[3] == 0.0f ? 1.0f :
      core::reciprocal(transformedPos[3]);

   
   I2DPnt Screen(viewPort.getWidth(),viewPort.getHeight());
   
   
   p.set(Screen.x * (transformedPos[0] * zDiv),Screen.y * (transformedPos[1] * zDiv));
   //return core::position2d<s32>(
   //      core::round32(dim.Width * transformedPos[0] * zDiv) + dim.Width,
   //      dim.Height - core::round32(dim.Height * (transformedPos[1] * zDiv)));
   return p;
   }
asparagusx
Posts: 81
Joined: Thu Oct 16, 2008 6:50 am

Post by asparagusx »

GeoMaster

I am getting better results, but it is not perfect yet. I am working on it now and will report back later. There seems to be an issue with the size of the final output e.g. I think the distance from the 2d plane also plays a role.

Anyway - thanks for the suggestion!!!

Asp
asparagusx
Posts: 81
Joined: Thu Oct 16, 2008 6:50 am

Post by asparagusx »

I am still having some issues with this. My current solution (which produces the correct results), calculates the intersections of an arbitrary view plane with the 3D geometry. I am sure that some kind of matrix operation will do the same, but I have been unable to calculate this. My algorithm for projecting a 3D point to a 2D point within an arbitrary plane is as follows :

Code: Select all

I2DPnt DCELFace::ProjectedPnt(const I3DPnt &pnt,const I3DPnt &From,const I3DPlane &Plane,I3DPnt &intp) const
	{
	I3DLine line(pnt,From - pnt);
	
	bool Intersect = line.IntersectWith(Plane,intp,false);
	if (!Intersect)
		Trace(false,"ProjectedPnt problem");
	return Plane.paramOf(intp);
	}	
pnt is the coordinate in 3D
From is the viewpoint (eye position)
Plane is the arbitrary view plane
intp is the returned 3D point of intersection

Plane.paramOf returns a 2D coordinate within the plane.

I am sure there must be a better (and faster) way of doing this.

Thanks

Anton
squisher
Competition winner
Posts: 91
Joined: Sat May 17, 2008 2:23 am
Contact:

Post by squisher »

Have you tried:

- move and rotate the camera so that you are looking straight down on the rectangle
- get the screen coords
- restore the camera's original pos and rot

?
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

I really don't understand what you're trying to do. Perhaps if you described what you are trying to do we can help you. I understand that you have 3d geometry, and you want to extract several polygons and transform them into 2d coordinates. What I don't understand is why you want this, and what you intend on doing with them. Why do you not want to continue working in 3d?

If you know the position of each of the verticies of the face(s) you need to select (in world space), you can transform those coordinates into 2d screen coordinates using the function mentioned previously.

Travis
asparagusx
Posts: 81
Joined: Thu Oct 16, 2008 6:50 am

Post by asparagusx »

Travis

I am doing a Hidden Line Removal routine as per the Weiler-Atherton algorithm. This requires 3D polygons to be converted to 2D to enable a polygon clipping routine to then determine visible surfaces. Once the visible lines have been identified, I need to convert it back to 3D (this is an optional step, as HLR 2D output is often the only output required). The 2d polygons are then sorted along the viewing direction and clipping performed on them. I have the routine working really well, but I do believe that there must be a more efficient routine for converting from 3D to 2d, without using the intersection of the plane. The 1st picture in the original post does show my requirement. This is all being used in a CAD system.

For reference. here is a screenie of a 2D drawing, which was generated from 3D and the all Hidden Lines/Surfaces removed. A user will then typically adorn the 2D drawing derived from 3D with more traditional drawing tools.

AspImage


Thanks for your interest and response.
Post Reply