🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Software Renderer: Projection * View * World matrix order

Started by
3 comments, last by karlmarxx 3 years, 5 months ago

Hello, I'm working on a simple software renderer. I'm able to render a simple mesh at the moment with 1 minor caveat I'd like to correct. While using DirectX/OpenGL in the past, matrix multiplication was done as projection x view x world, but my renderer is multiplying them as world x view x projection. I'm trying to ‘correct’ the ordering to multiply as I have in the past with DirectX and such. I've tried transposing the matrices but haven't had any luck. Any idea what I might be doing wrong? Some code:

void Camera::LookAt(const Vert3df& at)
 // Called when camera position changes
{
	lookAt = at;

	auto zAxis = (lookAt - position).Normalize();
	auto xAxis = up.Cross(zAxis).Normalize();
	auto yAxis = zAxis.Cross(xAxis);

	viewMatrix.Zero();
	viewMatrix(0, 0) = xAxis.x;
	viewMatrix(0, 1) = yAxis.x;
	viewMatrix(0, 2) = zAxis.x;
	viewMatrix(0, 3) = 0.0f;
	viewMatrix(1, 0) = xAxis.y;
	viewMatrix(1, 1) = yAxis.y;
	viewMatrix(1, 2) = zAxis.y;
	viewMatrix(1, 3) = 0.0f;
	viewMatrix(2, 0) = xAxis.z;
	viewMatrix(2, 1) = yAxis.z;
	viewMatrix(2, 2) = zAxis.z;
	viewMatrix(2, 3) = 0.0f;
	viewMatrix(3, 0) = -xAxis.Dot(position);
	viewMatrix(3, 1) = -yAxis.Dot(position);
	viewMatrix(3, 2) = -zAxis.Dot(position);
	viewMatrix(3, 3) = 1.0f;

	viewMatrix.Transpose();
}

void Camera::UpdateProjectionMatrix()
 // Called every frame
{
	const float aspectRatio = screenWidth / (float)screenHeight;

	float tanHalfFOV = std::tan(fov / 2.0f);
	float zRange = nearPlane - farPlane;

	projectionMatrix.Zero();
	projectionMatrix(0, 0) = 1.0f / (tanHalfFOV * aspectRatio);
	projectionMatrix(1, 1) = 1.0f / tanHalfFOV;
	projectionMatrix(2, 2) = (-nearPlane - farPlane) / zRange;
	projectionMatrix(2, 3) = 1; // Left handed, invert for right handed
	projectionMatrix(3, 2) = (2 * nearPlane * farPlane) / zRange;

	projectionMatrix.Transpose();
}

void SceneRenderer::DrawMesh(Mesh& mesh, const SRGraphicsContext& gfx)
{
	const Mat4x4f& worldMatrix = mesh.GetWorldMatrix();
	const Mat4x4f& viewMatrix = camera->GetViewMatrix();
	const Mat4x4f& projectionMatrix = camera->GetProjectionMatrix();
	const Mat4x4f& pvw = projectionMatrix * viewMatrix * worldMatrix;
	//const Mat4x4f& pvw = worldMatrix * viewMatrix * projectionMatrix;

	const Vert3df& cameraPos = camera->GetPosition();

	const float screenWidth = static_cast<float>(gfx.frameBuffer->GetWidth());
	const float screenHeight = static_cast<float>(gfx.frameBuffer->GetHeight());

	Tri2di rasterTri;
	for (Tri3df& tri : mesh.GetTriangles())
	{
		Vert4df p1c = Vert4df(tri.p1, 1),
				p2c = Vert4df(tri.p2, 1),
				p3c = Vert4df(tri.p3, 1);

		p1c = pvw * p1c;
		p2c = pvw * p2c;
		p3c = pvw * p3c;

		p1c.DivideByW();
		p2c.DivideByW();
		p3c.DivideByW();

		rasterTri.p1.x = static_cast<int>((p1c.x + 1.0f) / 2.0f * screenWidth);
		rasterTri.p1.y = static_cast<int>((p1c.y + 1.0f) / 2.0f * screenHeight);
		//rasterTri.p1.z = p1c.z;

		rasterTri.p2.x = static_cast<int>((p2c.x + 1.0f) / 2.0f * screenWidth);
		rasterTri.p2.y = static_cast<int>((p2c.y + 1.0f) / 2.0f * screenHeight);
		//rasterTri.p2.z = p2c.z;

		rasterTri.p3.x = static_cast<int>((p3c.x + 1.0f) / 2.0f * screenWidth);
		rasterTri.p3.y = static_cast<int>((p3c.y + 1.0f) / 2.0f * screenHeight);
		//rasterTri.p3.z = p3c.z;

		rasterizer->DrawTriangle(rasterTri, gfx);
	}
}
Advertisement

u don't have to correct the order of your matrix mults;

u could instead correct the order of your verts mults:

p1c = pvw * p1c;
to
p1c = p1c * pvw;

but if u insist on changing the order of your matrix mults then you're gonna have to review how u do it in your Matrix4x4f operator*( )

until then ?

Thanks for the reply, I'm rather insistent in changing the multiplication order out of curiosity. I've compared my matrix multiplication implementation, and results are identical to DirectX's XMMatrixMultiply().

https://stackoverflow.com/questions/23521089/open-gl-es-2-0-model-view-projection-matrices-multiplication-order

This seems to give an explanation as to why my orderering is revered.

This topic is closed to new replies.

Advertisement