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);
}
}