天天看點

D3D11之坐标空間的轉換

世界坐标系轉換:

世界坐标系轉換其實就是将頂點從幾何模型坐标系移到世界坐标系中,在遊戲裡就是建構遊戲場景,将物品放置到一個場景裡。通常在世界坐标系轉換時,還将通過改變大小來控制基元物件的放大或縮小,通過改變方向來設定旋轉,通過改變位置來進行轉變。在一個場景中,每一個物件都有他自己的世界坐标系轉換矩陣,這是由于每一個物件都有其自己的大小,方向和位置。

 觀察坐标系轉換:

所有頂點在轉換到世界坐标系後,觀察坐标系轉換将其從世界坐标系轉換為觀察坐标系中。前面我們講過,觀察坐标系即是在世界坐标系内,從觀測者或者錄影機角度透視所能夠看到的圖像,在觀察坐标系内,觀測者将站在原點(或者說以觀測者為原點),透視的方向即是Z軸方向,即觀察方向為Z軸方向。

 很值得注意的是,雖然觀察坐标空間是從觀測者在世界坐标系内所能夠看到的一個架構,但是觀察坐标系矩陣卻是由定點來填充的,而非觀測者。是以,觀察矩陣所填充的資料是和觀測者或者錄影機裡的正好相反,比如說,我們想把錄影機往-z方向移動4個機關,那麼我們必須計算出觀察矩陣轉換的定點正好為4個機關的Z軸方向。雖然錄影機是往反方向移動,但是在錄影機裡的成像卻是相反的。在Direct3D中有一個方法可以用來計算這種觀察矩陣,那就是XMMatrixLookAtLH()方法,我們隻要告訴他觀測者的位置,所觀看的位置,并且告訴他觀察者向上方向,就可以計算出觀察矩陣。

投影坐标系轉換:

投影坐标系轉換即是将定點從3D坐标系如:世界和觀察坐标系轉換為投影坐标系,在投影坐标系中,一個頂點的X和Y坐标是根據在3D空間中的X/Z和Y/Z的比率獲得的。首先我們來看一個圖,那樣有助于我們了解這個概念,如下所示:

D3D11之坐标空間的轉換

在3D中,根據透視法,越靠近的物體越大,從上圖可以看出,一棵高為h機關在遠離觀測點d機關的樹,和一棵高為2h機關距離觀測點2d位置的樹是一樣大的。是以,頂點在2D螢幕上呈現是依據X/Z和Y/Z的比率決定的。

在Direct3D中以一個叫做FOV(field-of-view),這個主要是通過特定方向判斷特定位置的頂點是否可見。每個人都有一個FOV,當然那是在我們的前方,因為我們不可能看到後面,如果兩個物體離得太近或非常遠也是看不到的。在計算機繪圖裡,FOV包含在一個視截體裡,在3D中這個視截體被定義一個六面體,有兩個面是XY面平行,他們被叫做近Z視平面和遠Z視平面。其它的面被定義為觀測者的橫向和縱向可視界面,FOV越大,視截體的體積也越大,當然容納的物體也更多,如下圖所示。

D3D11之坐标空間的轉換

GPU會過濾視截體外部的東東以至于不會浪費那些不需要顯示的部分,這個被稱為裁剪,GPU将會将頂點轉換為投影頂點,那樣就可以知道是否在視截體内。在Direct3D 11中,這些換行都被一個方法完成,那就是XMMatrixPerspectiveFovLH(),我們将提高4個參數,FOVy,比率,Zn和Zf即可以獲得投影矩陣。其中FOVy就是Y方向的投影角度,比率就是寬和高比率,Zn和Zf分别是近視面和遠視面的大小。

下面我們通過我們之前實作(D3D11之三,建立三角形)的例子來說明:

我們來看到colorshaderclass.cpp中的SetShaderParameters函數,函數把世界坐标,觀察坐标,投影坐标傳入頂點着色器中

進行計算。

bool ColorShaderClass::SetShaderParameters(ID3D11DeviceContext* deviceContext, XMMATRIX worldMatrix, XMMATRIX viewMatrix,
	XMMATRIX projectionMatrix)
{
	HRESULT result;
	D3D11_MAPPED_SUBRESOURCE mappedResource;
	MatrixBufferType* dataPtr;
	unsigned int bufferNumber;
	//確定在将矩陣發送到着色器之前進行轉置,這是DirectX 11的要求
	// Transpose the matrices to prepare them for the shader.
	worldMatrix = XMMatrixTranspose(worldMatrix);
	viewMatrix = XMMatrixTranspose(viewMatrix);
	projectionMatrix = XMMatrixTranspose(projectionMatrix);
	// Lock the constant buffer so it can be written to.
	result = deviceContext->Map(m_matrixBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
	if (FAILED(result))
	{
		return false;
	}

	// Get a pointer to the data in the constant buffer.
	dataPtr = (MatrixBufferType*)mappedResource.pData;

	// Copy the matrices into the constant buffer.
	dataPtr->world = worldMatrix;
	dataPtr->view = viewMatrix;
	dataPtr->projection = projectionMatrix;

	// Unlock the constant buffer.
	deviceContext->Unmap(m_matrixBuffer, 0);
	// Set the position of the constant buffer in the vertex shader.
	bufferNumber = 0;

	// Finanly set the constant buffer in the vertex shader with the updated values.
	deviceContext->VSSetConstantBuffers(bufferNumber, 1, &m_matrixBuffer);

	return true;
}
           

而我們的worldMatrix,viewMatrix,projectionMatrix又是從哪裡來的,我們可以看到graphicsclass.cpp中的分别來源

worldMatrix來自于d3dclass.cpp

// Initialize the world matrix to the identity matrix.世界矩陣,将我們對象的頂點轉換為3D場景中的頂點
m_worldMatrix = XMMatrixIdentity();//機關矩陣
           

viewMatrix

void CameraClass::Render()
{
	XMFLOAT3 up, position, lookAt;
	XMVECTOR upVector, positionVector, lookAtVector;
	float yaw, pitch, roll;
	XMMATRIX rotationMatrix;


	// Setup the vector that points upwards.
	up.x = 0.0f;
	up.y = 1.0f;
	up.z = 0.0f;

	// Load it into a XMVECTOR structure.
	upVector = XMLoadFloat3(&up);

	// Setup the position of the camera in the world.
	position.x = m_positionX;
	position.y = m_positionY;
	position.z = m_positionZ;

	// Load it into a XMVECTOR structure.
	positionVector = XMLoadFloat3(&position);

	// Setup where the camera is looking by default.
	lookAt.x = 0.0f;
	lookAt.y = 0.0f;
	lookAt.z = 1.0f;

	// Load it into a XMVECTOR structure.
	lookAtVector = XMLoadFloat3(&lookAt);

	// Set the yaw (Y axis), pitch (X axis), and roll (Z axis) rotations in radians.
	pitch = m_rotationX * 0.0174532925f;
	yaw = m_rotationY * 0.0174532925f;
	roll = m_rotationZ * 0.0174532925f;

	// Create the rotation matrix from the yaw, pitch, and roll values.
	rotationMatrix = XMMatrixRotationRollPitchYaw(pitch, yaw, roll);

	// Transform the lookAt and up vector by the rotation matrix so the view is correctly rotated at the origin.
	lookAtVector = XMVector3TransformCoord(lookAtVector, rotationMatrix);
	upVector = XMVector3TransformCoord(upVector, rotationMatrix);

	// Translate the rotated camera position to the location of the viewer.
	lookAtVector = XMVectorAdd(positionVector, lookAtVector);

	// Finally create the view matrix from the three updated vectors.
	m_viewMatrix = XMMatrixLookAtLH(positionVector, lookAtVector, upVector);

	return;
}
           

projectionMatrix

// Setup the projection matrix.設定投影矩陣
fieldOfView = 3.141592654f / 4.0f;
screenAspect = (float)screenWidth / (float)screenHeight;

// Create the projection matrix for 3D rendering.為3D渲染建立投影矩陣,可以把3D轉換為2D視窗
m_projectionMatrix = XMMatrixPerspectiveFovLH(fieldOfView, screenAspect, screenNear, screenDepth);
// Initialize the world matrix to the identity matrix.世界矩陣,将我們對象的頂點轉換為3D場景中的頂點
           

推導過程未完待續。。。。。

繼續閱讀