Tranforming/Translating vertex to screen coordinates.

Started by
8 comments, last by Musikai 11 years ago

I'm a begginer in DirectX programming and Im currently trying to draw a simple triangle to the screen using world, view and projection matrices. I have a feeling i'm calculating the matrices wrong as the triangle dosn't appear on the screen, but if i set all the matricies to the identity matrix then the triangle appears ( with no transformations obviously ).

Whats the best way to get help with this issue, do i upload my project? or should i run through the calculation process with the values i use and see if anyone spots something blatantly wrong?

Thank you.

Advertisement

You can skip all transformation matrices if you want to draw to the screen space. With D3D 11 for example, you can use vertex shader as pass-through without transforming. You'll just need some scaling and adding since the view space ranges from (-1.0,-1.0) to (1.0,1.0). So that means that you'll divide the x position with half of the back buffer width and subtract 1.0f. And same for the y position component.

Cheers!

The best way is to show your code for calculating the matrices that you are binding. Are you using D3D functions, or homemade code, or a library? Also, it is a common mistake that you may have the matrices defined in a row format instead of a column format (or vice versa). You can check this by compiling your shaders with D3DCOMPILE_PACK_MATRIX_ROW_MAJOR or D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR and see if there is any difference.

Thanks Jason. Im using the DirectXMath variables and functions. I'm not sure where to add those flags, but i do use XMMatrixTranspose(); on each matrix before i set them to the constant buffer, which i think does the same thing. I've tried with and without transposing the matrices. Im almost certain the problem is the projection matrix. I'll show the calculations, see what you think.

This is the three vertices of the triangle.


{ XMFLOAT3( -1.0f, -1.0f, 0.0f ) },
{ XMFLOAT3( +0.0f, +1.0f, 0.0f ) },
{ XMFLOAT3( +1.0f, -1.0f, 0.0f ) }

The view matrix: ( Rotation is zero so it can be ignored. )


XMFLOAT3 up, position, lookAt;
XMVECTOR vUp, vPosition, vLookAt;
float yaw, pitch, roll;
XMMATRIX rotationMatrix;

// Set the vector that points upwards.
up.x = 0.0f;
up.y = 1.0f;
up.z = 0.0f;
vUp = XMLoadFloat3( &up );

// Set the position of the camera in the world.
position.x = 0.0f;
position.y = 0.0f;
position.z = -10.0f;
vPosition = XMLoadFloat3( &position );

// Set where the camera is looking at by default.
lookAt.x = 0.0f;
lookAt.y = 0.0f;
lookAt.z = 1.0f;
vLookAt = XMLoadFloat3( &lookAt);

// Convert the rotation angles to radians. ( these are all 0, no rotation )
pitch = XMConvertToRadians( m_rotationX ); 
yaw   = XMConvertToRadians( m_rotationY );
roll  = XMConvertToRadians( m_rotationZ );

// Create the rotation matix based on the Yaw Pitch Roll. ( again this comes out as an identity matrix, no rotation )
rotationMatrix = XMMatrixRotationRollPitchYaw( pitch, yaw, roll );

// Transform the "lookAt" and "up" vectors to rotate the camera at its origin.
vUp = XMVector3TransformCoord( vUp, rotationMatrix );
vLookAt = XMVector3TransformCoord( vLookAt, rotationMatrix );

// Translate the rotated camera position to the position of the viewer.
vLookAt = vPosition + vLookAt;

// Finaly create the view matrix from the three updated vectors.
m_viewMatrix = XMMatrixLookAtLH( vPosition, vLookAt, vUp );

The world matrix is just set as an identity matrix, the triangle is at the origin of the world.


m_worldMatrix = XMMatrixIdentity();

The projection matrix:


screenWidth = 800;
screenHeight = 600;
screenNear = 0.1f;
screenDepth = 1000.0f;

float fieldOfView = (float)XM_PI / 4.0f;
float screenAspect = (float)screenWidth / (float)screenHeight;

m_projectionMatrix = DirectX::XMMatrixPerspectiveFovLH( fieldOfView, screenAspect, screenNear, screenDepth );

Transpose the matrices and set them to the constant buffer:


// Transpose the matrices to prepare them for the shader.
XMMatrixTranspose( worldMatrix );
XMMatrixTranspose( viewMatrix );
XMMatrixTranspose( projectionMatrix );

// Lock the constant buffer so it can be writen to.
deviceContext->Map( m_matrixBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource );


// 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 constant buffer in the vertex shader with the updated values.
deviceContext->VSSetConstantBuffers( 0, 1, &m_matrixBuffer );

The think final vertices positions comes out as this.


{-1.81066000, -2.41421342, 9.90099049, 10.0000000}
{0.000000000, 2.41421342, 9.90099049, 10.0000000}
{1.81066000, -2.41421342, 9.90099049, 10.0000000}

Just for clarification, you would pass those flags into your shader compilation method. This is one of the flag arguments to D3DCompile, or the equivalent if you are using FXC to compile your shaders.

Those vertices that are on the output are actually going to be visible - if you divide all components by the w-component, you will end up with numbers that are within [-1,1] for x and y, and [0,1] for z. So I don't think your issue is with the matrices.

Have you tried swapping two of your vertices to see if you are culling the triangle as a backface? That is also a issue when just setting up the pipeline. I would also try to double check any states that can eliminate your output if they aren't set properly, such as the viewport, scissor rect, depth test, and stencil test. And finally, what is your pixel shader trying to put out?

Out of each of those properties, I think viewport is the most likely culprit, but I could be wrong on that. Do you also have access to PIX and/or the Graphics Debugger? Either of those tools will significantly improve the debugging experience, so check them out if you can!

The vertices should be visible? Thats even more puzzling. I've tryed swapping vertices and i've even set the raster state to D3D11_CULL_NONE so i can see both sides, still nothing. Apparently in the latest Windows SDK, PIX is replaced by the Gaphics Debugger which is only available in the retail version of Visual Studio, im using the Express version so thats a pain.

Like i say, if i dont use the matrices, or even set them to be Identity matrices, then the triangle appears as expected.

Wish i could se what the values in the shader are at run time. This is what my shaders look like.



// Constant Buffer---------------------------------------------------------------

cbuffer MatrixBuffer
{
	matrix worldMatrix;
	matrix viewMatrix;
	matrix projectionMatrix;
};

// Type defines-----------------------------------------------------------------

struct VSInput
{
	float4 position : POSITION;
	float4 color	: COLOR;
};

struct PSInput
{
	float4 position : SV_POSITION;
	float4 color	: COLOR;
};

// Vertex Shader---------------------------------------------------------------

PSInput VS( VSInput input )
{
	PSInput output;

	// Change the position to be 4 units for proper matrix calculations.
	input.position.w = 1.0f;

	// Calculate the position of the vertex against the world, view and projection matrices.
	output.position = mul( input.position, worldMatrix );
	output.position = mul( output.position, viewMatrix );
	output.position = mul( output.position, projectionMatrix );

	// Store the color.
	output.color = input.color;

	return output;
}

// Pixel Shader-------------------------------------------------------------------

float4 PS( PSInput input ) : SV_TARGET
{
    return input.color;
}

Hmmm... if it works when the matrices aren't applied, then I guess that eliminates things like the viewport and depth/stencil states... So assuming that the matrices' contents are correct, and since the shader looks correct, we could assume that they are somehow not getting loaded properly.

Let's try another test - set all of the matrices to the identity matrix in your CPU code, and still apply them in your shader. This should indicate if the contents of the matrices is being properly transferred to the shader. Since you know your untransformed geometry works, then applying identity matrices should produce the same result.

Like i said, i've tried that and the triangle appears fine.biggrin.png Which is why i'm pretty confident its the matrix calculations that are wrong, specifically the projection matrix.

If i add just this line to the code, the triangle appears.


projectionMatrix = XMMatrixIdentity();

I found out that the retail version of Visual Studio has a ninty day trial. Im'a go download that, figure out how to use the Graphics Debugger and see what the values are in the shader. Thanks for your help so far, really appreciate it.

Instead of

XMMatrixTranspose( worldMatrix );
XMMatrixTranspose( viewMatrix );
XMMatrixTranspose( projectionMatrix );
rather

worldMatrix = XMMatrixTranspose( worldMatrix );
viewMatrix = XMMatrixTranspose( viewMatrix );
projectionMatrix = XMMatrixTranspose( projectionMatrix );
Or better yet, transpose them only when you copy them to your MatrixBufferType struct.

Haha that was it! I didnt store the returned values when i transposed them. Thank so much! *facepalm*

This topic is closed to new replies.

Advertisement