1
\$\begingroup\$

So I'm designing a soft game engine in C# on top of the SharpDX API (a C# wrapper for DirectX). As I'm designing the camera, though, I'm running into some issues getting the 3D perspective correct. I've read through a few tutorials and articles, but I can't seem to find what I'm doing explicitly wrong.

This is my current understanding: The world matrix is the identity matrix (of the world...) times the translation matrix of the model, times the rotation matrix of the model, times the scale matrix of the model, which should then give me the transformed location of each vertex in "world space." The view matrix would then be the output matrix of LookAtLH(cameraPositionVec, targetPositionVec, upVec);. Finally, the projection matrix seems to be the output of the PerspectiveFovLH(fov, aspectRatio, nearDist, farDist); So, I then took the transpose of each of these matrices, multiplied world * view * projection and I should be left with the final transformed vertex coordinate.

Here's the code I have so far. I've left the world matrix untouched by just setting the translation to the origin, the rotation of the model to the identity matrix, and the Scale to 1, which should mean I don't have to actually perform any world matrix calculations for the sake of simplicity right now.

// Setup and create the projection matrix.
projectionMatrix = Matrix.PerspectiveFovLH((float)(Math.PI / 4.0f), ((float)GameWindow.WIN_WIDTH / (float)GameWindow.WIN_HEIGHT), 0.1f, 100.0f);

// Initialize the world matrix to the identity matrix.
worldMatrix = Matrix.Identity

...
//camera class
public Camera(Vector3 _position, Vector3 _target, Vector3 _rotation)
{
    position = _position; 
    target = _target;     
    rotation = _rotation;
}
public Matrix GetViewMatrix()
{
    //convert degrees to radians
    float pitch = rotation.X * 0.0174532925f;
    float yaw = rotation.Y * 0.0174532925f;
    float roll = rotation.Z * 0.0174532925f;

    //get rotation matrix and the relative up vector
    Matrix rotationMatrix = Matrix.RotationYawPitchRoll(yaw, pitch, roll);
    Vector3 up = Vector3.TransformCoordinate(Vector3.UnitY, rotationMatrix);

    return Matrix.LookAtLH(position, target, up);
}

....

//set the view matrix
viewMatrix = camera.GetViewMatrix();

...
//Transpose the matrices
worldMatrix.Transpose();
viewMatrix.Transpose();
projectionMatrix.Transpose();

From there they are fed to the vertex shader, which is below. If I comment out the projectionMatrix multiplication though, the image shows up. If It's not commented out though, nothing renders to the screen, which leads me to believe that may be the issue.

//vertex shader
cbuffer MatrixBuffer
{
    matrix worldMatrix;
    matrix viewMatrix;
    matrix projectionMatrix;
};

struct VertexInputType
{
    float4 position : POSITION;
    float2 tex : TEXCOORD0;
};

struct PixelInputType
{
    float4 position : SV_POSITION;
    float2 tex : texCoord0;
};


PixelInputType main(VertexInputType input)
{
    PixelInputType output;


    // Change the position vector 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); //<-- If I comment this line, it renders to the screen
    // Store the texture coordinates for the pixel shader.
    output.tex = input.tex;

     return output;
}

I feel like I'm missing something really basic, because I think I'm pretty close. Thanks for any help you can provide.

\$\endgroup\$
1
\$\begingroup\$

So, in the end, I'm not entirely sure why the above code doesn't work, but I believe it has something to do with the way that matrices are multiplied, which appears to vary, being either row-major or column-major. There's a much better description, which was posted as an answer to this question. Even with this in mind though, I was unable to fix the problem as my code stands, (possibly because of all the arbitrary transposing I've done near the middle of my code, which was inspired by some rather shoddy examples).

I then later stumbled upon another question regarding where I should be calculating my model-view-projection matrix at all. It seems that the best way to do such a task would actually be to do the calculation on the CPU and send that answer over to the GPU as a pre-processed matrix. I rewrote the hlsl file to this instead:

cbuffer MatrixBuffer
{
    matrix worldViewProjMatrix;
};

[...]

PixelInputType main(VertexInputType input)
{
    PixelInputType output;


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

    // transform output mosition to screen space using w-v-p matrix
    output.position = mul(input.position, worldViewProjMatrix);
    // Store the texture coordinates for the pixel shader.
    output.tex = input.tex;

    return output;
}

Then, as per the suggestion on the first question I referenced, I calculated the model-view-projection matrix on the CPU using the following:

Matrix worldViewMatrix = worldMatrix * viewMatrix;
Matrix worldViewProjMatrix = (worldViewMatrix * projectionMatrix);
worldViewProjMatrix.Transpose();

I then wrote this to the buffer. The way in which I actually acquired the world, view, and projection matrices was not the issue at all. Hopefully this helps somebody else who has the same issue later.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.