Jump to content


How to flatten view?


11 replies to this topic

#1 ikk

    Member

  • Members
  • PipPip
  • 87 posts

Posted 12 October 2005 - 08:45 AM

How can i flatten view so 3d world looks like it would be a 2d.
That is, i want to get rid of perspective in the way that it looks like in every 3d object on scene one of vector components (ie. x) is zero.
I know i can modify every vertex by writing zero into x-component, but how can i achieve this by matrix transformations?

#2 moe

    Valued Member

  • Members
  • PipPipPip
  • 270 posts

Posted 12 October 2005 - 08:58 AM

For rendering on screen you have:
world * view * projection
Now you have to replace the projection matrix with an orthogonal matrix.
You can find further info here:
http://mathworld.wol...onalMatrix.html
or here:
http://encyclopedia....thogonal+matrix

#3 ikk

    Member

  • Members
  • PipPip
  • 87 posts

Posted 12 October 2005 - 11:57 AM

ok, thanks

#4 ikk

    Member

  • Members
  • PipPip
  • 87 posts

Posted 12 October 2005 - 12:11 PM

im currently working on it. i appreciate any suggestions

#5 moe

    Valued Member

  • Members
  • PipPipPip
  • 270 posts

Posted 12 October 2005 - 12:59 PM

I was not more specific for two reasons.
- I’m not that good at math
- when I try to explain math I tend to make things more complicates :(

If you are using directx you can just use the provided functions instead of reinventing the wheel.

From the docu:

D3DXMATRIX *WINAPI D3DXMatrixOrthoLH(
D3DXMATRIX *pOut,
FLOAT w,
FLOAT h,
FLOAT zn,
FLOAT zf
);

Parameters:
pOut [in, out] Pointer to the D3DXMATRIX structure that contains the resulting matrix.
w [in] Width of the view volume.
h [in] Height of the view volume.
zn [in] Minimum z-value of the view volume which is referred to as z-near.
zf [in] Maximum z-value of the view volume which is referred to as z-far.


And then set it as usual.
pd3dDevice->SetTransform( D3DTS_PROJECTION, & pOut);

hope it helps.

#6 ikk

    Member

  • Members
  • PipPip
  • 87 posts

Posted 12 October 2005 - 03:24 PM

Im using function u mentioned (D3DXMatrixOrthoLH) but there is another problem.
Collision testing against rays doesnt work now.

I have this code to produce from screen points rays into world space, it works when i setup projection using D3DXMatrixPerspectiveFovLH function but not when D3DXMatrixOrthoLH.

here is function i took from directx sample, as ia said, it converts screen points into world rays (origin and direction), and that rays are propably incorrect now.

maybe someone know what do i need update in my functon.

VOID CDevice3d::

GetScreen2DPointToWorld3DPoint( const POINT* lpScreenPoint, D3DXVECTOR3* lpvOrigin, 

							   D3DXVECTOR3* lpvDirection )

{

	POINT ptScreenSize;

	GetScreenSize( &ptScreenSize );

	D3DXVECTOR3 v; D3DXMATRIX matProj;


	pd3dDeviceC->GetTransform( D3DTS_PROJECTION, &matProj );

	v.x =  ( ( ( 2.0f * lpScreenPoint->x ) / ptScreenSize.x ) - 1 ) / matProj._11;

	v.y = -( ( ( 2.0f * lpScreenPoint->y ) / ptScreenSize.y ) - 1 ) / matProj._22;

	v.z =  1.0f;

	// get the inverse of view matrix

	D3DXMATRIX matViewInv, m;

	pd3dDeviceC->GetTransform( D3DTS_VIEW, &m );

	D3DXMatrixInverse( &matViewInv, NULL, &m );


	// Transform the screen space pick ray into 3D space

	{

		// get ray direction vector

		if(lpvDirection){

			lpvDirection->x = v.x * matViewInv._11 + v.y * matViewInv._21 + v.z * matViewInv._31;

			lpvDirection->y = v.x * matViewInv._12 + v.y * matViewInv._22 + v.z * matViewInv._32;

			lpvDirection->z = v.x * matViewInv._13 + v.y * matViewInv._23 + v.z * matViewInv._33;

		}

		// get ray origin (start point), which is actually same as camera pos

		if(lpvOrigin){

			lpvOrigin->x = matViewInv._41;

			lpvOrigin->y = matViewInv._42;

			lpvOrigin->z = matViewInv._43;

		}

	}

}



#7 moe

    Valued Member

  • Members
  • PipPipPip
  • 270 posts

Posted 12 October 2005 - 04:06 PM

In your comment you write

Quote

// get ray origin (start point), which is actually same as camera pos
Think about how the view frustum looks like. If you have a normal projection then the frustum is like a pyramid. So yes all the rays go through the camera pos.

But if you have an orthogonal matrix then the frustum is more like a stretched cube (don’t know the appropriate word in English…). This means the rays are parallel to one another and only the ray in the middle of your frustum goes through the camera pos.

#8 ikk

    Member

  • Members
  • PipPip
  • 87 posts

Posted 12 October 2005 - 08:37 PM

still i dont know how to do it :(

#9 moe

    Valued Member

  • Members
  • PipPipPip
  • 270 posts

Posted 12 October 2005 - 09:06 PM

Let’s make a sample.

D3DXMATRIX *pOut;
FLOAT w = 640;
FLOAT h = 480;
FLOAT zn = 1.0f;
FLOAT zf = 100.0f;

D3DXMatrixOrthoLH( &pOut, w, h, , zn, zf );


Assuming your camera is at origin (identity matrix) then your direction would be

D3DXVECTOR3 vDir = D3DXVECTOR3( 0.0f, 0.0f ,1.0f );

You pick a point on screen e.g.

D3DXVECTOR3 vPointOnScreen;
vPointOnScreen.x = 20.0f;
vPointOnScreen.y = 100.0f;
vPointOnScreen.z = 0.0f; // this is always 0.0f

get world coordinates from point on screen:

D3DXVECTOR3 vPointInWorld;
vPointInWorld.x = -((w / 2.0f) – vPointOnScreen.x);
vPointInWorld.y = (h / 2.0f) – vPointOnScreen.y;
vPointInWorld.z = 0.0f; // this is always 0.0f

now take the view matrix into account:

D3DXVec3TransformCoord( &vPointInWorld, &vPointInWorld, &matView );
D3DXVec3TransformCoord( &vDir, &vDir, &matView );

Did that make more sense?


p.s. I have not tested it but the strategy should be right.

#10 moe

    Valued Member

  • Members
  • PipPipPip
  • 270 posts

Posted 13 October 2005 - 08:43 AM

Darn that’s just a sample of what I mean with I tend to make things more complicated when trying to explain math. Your way of finding the direction is correct. In my sample above I take the translation from the view matrix into account. You should only take the rotation. However finding the start point (origin) should be correct. In that case you take translation and rotation from the view matrix. Sorry for confusing you.

#11 ikk

    Member

  • Members
  • PipPip
  • 87 posts

Posted 13 October 2005 - 03:39 PM

ok thanx, i think ill leave this problem for now

#12 ikk

    Member

  • Members
  • PipPip
  • 87 posts

Posted 07 November 2005 - 10:48 AM

ive used yours advices and i solved this problem mow.
im using this code to create orthogonal view:

// DESC: makes world looks like flattern

VOID CCamera::MakeOrthogonal( DWORD dwOrthogonalPr )

{

	lpvPosSaves[dwViewMode] = GetOrigin();		//save previous mode pos

	dwViewMode = dwOrthogonalPr;					//set new camera mode


	D3DXMATRIX m;

	// build left-handed orthogonal projection matrix

	D3DXMatrixOrthoLH( &m, 

						fUnitsPerWidth,		//width of view volume in world units

						fUnitsPerHeight,	//height of view volume in world units

						fZNearClipPlane,	//z-near

						MAX_WORLD_Z * 2 );		//z-far, fZFarClipPlane

	lpD3dDev->SetTransform( D3DTS_PROJECTION, &m );

	//

	D3DXVECTOR3 vEye, vAt, vUp;

	DefaultEyeAtSetup( dwViewMode, &vEye, &vAt, &vUp );

	D3DXMatrixLookAtLH( &m, &vEye, &vAt, &vUp );

	lpD3dDev->SetTransform( D3DTS_VIEW, &m );


	SetPlacement( &lpvPosSaves[dwViewMode], NULL );

}

and this code to get ray of mouse pick point:

// DESC: converts on screen point into point and direction in 3d world space.

// lpScreenPoint - [in] x,y coordinates of screen point relative to upper left corner of 

//                 client area

// lpvOrigin, lpvDirection - [out] two vectors, origin and direction. note: origin is

//       in world space and direction is isloated/individual one (jednostkowy), that is

//       it points direction of origin vector

VOID CCamera::

GetScreen2DPointAsWorldRay( const POINT* lpScreenPoint, D3DXVECTOR3* lpvOrigin, 

							   D3DXVECTOR3* lpvDirection )

{

	POINT ptScreenSize;

	((CDevice3d*)lpcDevice)->GetScreenSize( &ptScreenSize );

	FLOAT x = lpScreenPoint->x;

	FLOAT y = lpScreenPoint->y;

	FLOAT sx = ptScreenSize.x;

	FLOAT sy = ptScreenSize.y;


	D3DXMATRIX matProj;

	lpD3dDev->GetTransform( D3DTS_PROJECTION, &matProj );


	// get the inverse of view matrix

	D3DXMATRIX mi;

	lpD3dDev->GetTransform( D3DTS_VIEW, &mi );

	D3DXMatrixInverse( &mi, NULL, &mi );

	

	// calculate how many world units is per screen width and height.

	// from 'D3DXMatrixOrthoLH' function documentation its known that

	// matProj._11 = w/2 and matProj._22 = h/2.

	FLOAT fUnitsPerWidh   = 2.0f / matProj._11;

	FLOAT fUnitsPerHeight = 2.0f / matProj._22;

	// calculate position on screen in world units (WU)

	FLOAT fXOnScrWU = x * fUnitsPerWidh   / sx;

	FLOAT fYOnScrWU = y * fUnitsPerHeight / sy;

	// take into account that center of the screen for world is (0,0), not 

	// left/upper (like in Win32 GUI)

	FLOAT fXWrldWU = fXOnScrWU - fUnitsPerWidh / 2.0f;		//division by 2 bcos needed are coordinates from center of screen

	FLOAT fYWrldWU = -( fYOnScrWU - fUnitsPerHeight / 2.0f );	//minus, bcos in GUI y is from top to bottom but in world from bottom to top


	D3DXVECTOR3 vRayDir, vRayOrig;

	if( dwViewMode != CCAM_PERSP ){		// if orthogonal view

		vRayDir  = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );

		vRayOrig = D3DXVECTOR3( fXWrldWU, fYWrldWU, 0.0f );	//for orthogonal viw (without perspective)

	}else{

		vRayDir  = D3DXVECTOR3( fXWrldWU, fYWrldWU, 1.0f );

		vRayOrig = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );			//for perspective view


	}

	D3DXVec3TransformNormal( lpvDirection, &vRayDir, &mi );

	D3DXVec3TransformCoord( lpvOrigin, &vRayOrig, &mi );

}







1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users