Advertisement

Diretcx Rotation Matrix Problem

Started by August 05, 2016 12:30 PM
11 comments, last by FantasyVII 8 years, 6 months ago

Hi,

I'm making a DirectX/OpenGL engine for learning purposes. However I'm having a problem with my implementation of the rotation matrix for DirectX.


The rotation on the x and z axis looks fine for both DirectX and OpenGL. Also the rotation on the Y axis in OpenGL looks fine too. However the rotation on the Y axis in DirectX looks very weird.


This how OpenGL Y axis rotation looks like. Which looks perfectly fine.



And here how DirectX Y axis rotation looks like.



The triangle in DirectX looks like a right-angled triangle for some reason.

Now I understand why the triangle doesn't get rendered in DirectX when it is flipped. That is not the problem, the problem is that the triangle looks like it somehow turned into a right-angled triangle. I don't know why.


This is the image I'm using for my implementation.


gl_matrix04.png



Here is my matrix function


/*
		 m11 m12 m13 m14  x
		 m21 m22 m23 m24  y
		 m31 m32 m33 m34  z
	x y z w  m41 m42 m43 m44  w

	C++ array indices		[0,   1,   2,   3  ], [4,   5,   6,   7  ], [8,   9,   10,  11 ]  [12,  13,  14,  15 ]
	DirectX matrix layout		[m11, m21, m31, m41], [m12, m22, m32, m42], [m13, m23, m33, m43], [m14, m24, m34, m44]
	OpenGL matrix layout		[m11, m12, m13, m14], [m21, m22, m23, m24], [m31, m32, m33, m34], [m41, m42, m43, m44]
*/

const int ROW_COLUMN_SIZE = 4;

Matrix4 Matrix4::Rotate(const float &angle, const Vector3 &axis)
{
	Matrix4 RotationMatrix = Matrix4::Identity();

	float r = ToRadians(angle);
	float c = cos(r);
	float s = sin(r);
	float oc = 1 - c;

	if (Graphics::Renderer::renderingAPI == Graphics::Renderer::RenderingAPI::DirectX11)
	{
		//First column
		RotationMatrix.elements[0 * ROW_COLUMN_SIZE + 0] = axis.x * axis.x * oc + c;
		RotationMatrix.elements[0 * ROW_COLUMN_SIZE + 1] = axis.x * axis.y * oc + axis.z * s;
		RotationMatrix.elements[0 * ROW_COLUMN_SIZE + 2] = axis.x * axis.z * oc - axis.y * s;

		//Second column
		RotationMatrix.elements[1 * ROW_COLUMN_SIZE + 0] = axis.x * axis.y * oc - axis.z * s;
		RotationMatrix.elements[1 * ROW_COLUMN_SIZE + 1] = axis.y * axis.y * oc + c;
		RotationMatrix.elements[1 * ROW_COLUMN_SIZE + 2] = axis.y * axis.z * oc + axis.x * s;
		
		//Third column
		RotationMatrix.elements[2 * ROW_COLUMN_SIZE + 0] = axis.x * axis.z * oc + axis.y * s;
		RotationMatrix.elements[2 * ROW_COLUMN_SIZE + 1] = axis.y * axis.z * oc - axis.x * s;
		RotationMatrix.elements[2 * ROW_COLUMN_SIZE + 2] = axis.z * axis.z * oc + c;
	}
	else if (Graphics::Renderer::renderingAPI == Graphics::Renderer::RenderingAPI::OpenGL4_5)
	{
		//First row
		RotationMatrix.elements[0 + 0 * ROW_COLUMN_SIZE] = axis.x * axis.x * oc + c;
		RotationMatrix.elements[1 + 0 * ROW_COLUMN_SIZE] = axis.x * axis.y * oc - axis.z * s;
		RotationMatrix.elements[2 + 0 * ROW_COLUMN_SIZE] = axis.x * axis.z * oc + axis.y * s;

		//Second row
		RotationMatrix.elements[0 + 1 * ROW_COLUMN_SIZE] = axis.x * axis.y * oc + axis.z * s;
		RotationMatrix.elements[1 + 1 * ROW_COLUMN_SIZE] = axis.y * axis.y * oc + c;
		RotationMatrix.elements[2 + 1 * ROW_COLUMN_SIZE] = axis.y * axis.z * oc - axis.x * s;

		//Third row
		RotationMatrix.elements[0 + 2 * ROW_COLUMN_SIZE] = axis.x * axis.z * oc - axis.y * s;
		RotationMatrix.elements[1 + 2 * ROW_COLUMN_SIZE] = axis.y * axis.z * oc + axis.x * s;
		RotationMatrix.elements[2 + 2 * ROW_COLUMN_SIZE] = axis.z * axis.z * oc + c;
	}

	return RotationMatrix;
}


OpenGL and DirectX rotation

[spoiler]

OpenGL rotation

X axis



Y axis


Z axis



DirectX rotation

X axis


Y axis


Z axis
[/spoiler]

just to be sure, are you using the same multiplication order in shaders (both ogl and dx)?

you should use one order for both.

you could also add shaders here.

in other words post your shader code here (ogl and dx)

and youse one matrix notation for both dx and ogl

Advertisement

just to be sure, are you using the same multiplication order in shaders (both ogl and dx)?

you should use one order for both.

you could also add shaders here.

in other words post your shader code here (ogl and dx)

and youse one matrix notation for both dx and ogl

I'm only passing the rotation matrix to the shader.

My modelMatrix has nothing but the rotation matrix.

initBuffer.modelMatrix = Matrix4::Rotate(initBuffer.angle, Vector3(0, 0, 1));


hlsl

cbuffer shader_data
{
	float4x4 buffer_modelMatrix;
	float4 buffer_color;
};

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

VOut main(float4 position : POSITION, float4 color : COLOR)
{
	VOut output;

	output.position = mul(position, buffer_modelMatrix);
	output.color = color + buffer_color;

	return output;
}


//-------------------------------------------------------------

glsl


#version 450 core
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inColor;

out vec3 fragmentColor;

layout (std140) uniform shader_data
{
	mat4 buffer_modelMatrix;
	vec4 buffer_color;
};

void main()
{
	gl_Position = buffer_modelMatrix * vec4(inPosition.xyz, 1.0f);
	fragmentColor = inColor + buffer_color.xyz;
}

It can be many things, implying that we must guess a solution.

Check the winding order of the triangle. DX will back-face cull CCW oriented triangles/polygons by default, whereas OpenGL culls CW oriented ones when viewed front-face by default.

Disable depth.

Disable culling.

Validate the projection matrix.

Validate vertex/index/constant buffers.

Use RenderDoc/IntelGPA/Visual Studio Graphics Debugger if available for debugging/resource validation.

BTW, there is absolutely no reason for using the general angle-axis function to create a rotation matrix along a *basis* axis which is much more error-prone than doing the following, assuming a column-major matrix:



Mat3 Mat3::RotationY(float angle)
{
	float c = cos(angle);
	float s = sin(angle);

	Mat3 A =
	{ {
		{  c, 0, s },
		{  0, 1, 0 },
		{ -s, 0, c }
	} };

	return A;
}

Try those things out and post the results here. You also might want to post these kinds of questions in the graphics section in the future as well, as the rotation matrix seems to be correct by looking at the equation (which is math-related).

For the life of me I can't figure out why is this happening. I have spent all day and can't figure it out.

I have set the Cull mode in DX11 to D3D11_CULL_NONE.

I have taken your rotation matrix and put it in the shader. So the only thing i'm passing to the shader is an angle that I incurment by 0.00025f every frame.

I'm still having the same problem.


cbuffer shader_data
{
	float angle;
};

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

float3x3 RotationY(float angle)
{
	float c = cos(angle);
	float s = sin(angle);

	float3x3 A =
	{ {
		{ c, 0, s },
		{ 0, 1, 0 },
		{ -s, 0, c }
	} };

	return A;
}

VOut main(float4 position : POSITION, float4 color : COLOR)
{
	float3x3 buffer_modelMatrix = RotationY(angle);

	VOut output;

	output.position = float4(mul(position.xyz, buffer_modelMatrix), 1.0f);
	output.color = color;

	return output;
}

This tutorial seems to be a good introduction for begginers:

http://www.rastertek.com/dx11tut04.html

Advertisement

This tutorial seems to be a good introduction for begginers:

http://www.rastertek.com/dx11tut04.html

I agree, but that still doesn't help me with this problem. I have no interest in using the built-in Math library in DirectX.

Disable depth.

I'm so dumb. I thought I disabled depth. It turns out I didn't. After setting DepthClipEnable to false, everything worked just fine. Thanks

You can't expect your code to work since the projection matrix is missing. I copied over below the one I'm using currently (RH):


Mat4 PerspectiveRH(float fovy, float aspect, float zNear, float zFar)
{
	float f = tanf(0.5f * (PI - fovy));
	float invRange = 1.0f / (zNear - zFar);
	Mat4 A =
	{ {
		{ f / aspect, 0.0f, 0.0f,                        0.0f },
		{ 0.0f,       f,    0.0f,                        0.0f },
		{ 0.0f,       0.0f, invRange * (zNear + zFar),  -1.0f },
		{ 0.0f,       0.0f, invRange *  zNear * zFar,    0.0f }
	} };
	return A;
}

You should also swap your multiplication order to matrix-vector in the shader. Example:



void main(in float3 InPos : POSITION, out float4 OutPos : SV_Position) 
{
   float4 HomoPos = float4(InPos, 1.0);
   OutPos = mul(ProjectionMatrix, HomoPos);
}

Good luck!

You can't expect your code to work since the projection matrix is missing. I copied over below the one I'm using currently (RH):


Mat4 PerspectiveRH(float fovy, float aspect, float zNear, float zFar)
{
	float f = tanf(0.5f * (PI - fovy));
	float invRange = 1.0f / (zNear - zFar);
	Mat4 A =
	{ {
		{ f / aspect, 0.0f, 0.0f,                        0.0f },
		{ 0.0f,       f,    0.0f,                        0.0f },
		{ 0.0f,       0.0f, invRange * (zNear + zFar),  -1.0f },
		{ 0.0f,       0.0f, invRange *  zNear * zFar,    0.0f }
	} };
	return A;
}

You should also swap your multiplication order to matrix-vector in the shader. Example:



void main(in float3 InPos : POSITION, out float4 OutPos : SV_Position) 
{
   float4 HomoPos = float4(InPos, 1.0);
   OutPos = mul(ProjectionMatrix, HomoPos);
}

Good luck!

Well I didn't think I needed to add the projection matrix yet since OpenGL didn't need one. Obviously I was wrong. Thanks :)

This topic is closed to new replies.

Advertisement