2
\$\begingroup\$

I have been trying to render a quad(containg a texture) using orthographic camera so that the quad can be rendered using the screen coordinates directly.

I started of by rendering just a triangle with a image. The triangle is rendered but it seems teh center of the screen is 0,0 but using the code below it should have been at top left of the screen.

Ortho camera matrix code:

// Set the camera position
        var cameraPosition = new Vector3(0.0f, 0.0f, 0.0f);
        var cameraTarget = new Vector3(0f, 0.0f, 1.0f); // Looking at the origin 0,0,0  
        var cameraUp = new Vector3(0.0f, 1.0f, 0.0f); // Y+ is Up

        // Prepare matrices
        // Create the view matrix from our camera position, look target and up direction
        // direct X uses left hand co-ordinate system
        m_viewMatrix = Matrix.LookAtLH(cameraPosition, cameraTarget, cameraUp);

        // Initialize the world matrix
        m_worldMatrix = Matrix.Identity;
        var scalingMatrix = Matrix.Scaling(720, 576, 1);
        var translationMatrix = Matrix.Translation(new Vector3(0, 0, 0));
        var rotationMatrix = Matrix.RotationZ(0);
        m_worldMatrix = translationMatrix * scalingMatrix * rotationMatrix;

        m_worldMatrix = translationMatrix * scalingMatrix * rotationMatrix;
        var worlViewMatrix = Matrix.Multiply(m_worldMatrix, m_viewMatrix);
        m_projectionMatrix = Matrix.OrthoOffCenterLH(0, 720, 576, 0, 1f, 1000.0f);  
        m_perObject.WorldViewProjection = Matrix.Multiply(worlViewMatrix, m_projectionMatrix);

Vertices code:

stream.WriteRange(new[]
            {
                new VertexPositionTexture(
                    new Vector4(720, 576, 0.5f, 1.0f), // position bottom-right
                    new Vector2(1024,576)
                ),
                new VertexPositionTexture(
                    new Vector4(0, 0, 0.5f, 1.0f), // position top-left
                    new Vector2(0, 0)
                ),
                new VertexPositionTexture(
                    new Vector4(720, 0, 0.5f, 1.0f), // position top-right
                    new Vector2(1024, 0)
                ),
            });

Shader code:

float4x4 WorldViewProj;

struct VertexShaderInput
{   
 float4 Position : SV_Position; 
 float2 TextureUV : TEXCOORD0;
};

VertexShaderOutput VSMain(VertexShaderInput input)
{   
 VertexShaderOutput output = (VertexShaderOutput)0; 
 //output.Position = input.Position;    
 output.Position = mul(input.Position, WorldViewProj);  
 output.TextureUV = input.TextureUV;    
 return output;
}

Screenshot of image rendered: enter image description here

Now I can't seem to figure out why the center of the screen is 0,0 and not top left ? Also as a part of this if I do not use a scaling matrix the triangle is not rendered.

The main reason behind the above attempt is to draw a quad/triangle using screen co-ordinates so that i can place exactly where i want without the need to calculate the vertices all the time when ever i wish to place my quad/triangle.

This issue has left me baffled for last couple days. Any help or suggestion would be really helpful.

Note: I am using Directx11 with sharpdx and still learning directx learner.

\$\endgroup\$
  • \$\begingroup\$ @Jon If by GL you mean Opengl then in that case no. I'm using Directx11. In reference to multiplying matrices, that's the way I've read it should be done unless iv misinterpreted thing incorrectly. Feel free to correct me if I'm wrong \$\endgroup\$ – Dave23Rave Mar 27 '16 at 22:08
  • \$\begingroup\$ @Jon If I understand correctly then in regards to your comment about matrices multiplication, to generate worldviewprojection matrix I should be doing world * (view * projection). As for the comment on Vector3. Forward I will try it when I'm back in front of my pc . \$\endgroup\$ – Dave23Rave Mar 27 '16 at 22:48
  • \$\begingroup\$ You are doing WVP = W * V * P, but you are also doing W = T * S * R. It should be WVP = S * R * T * V * P, not WVP = T * S * R * V * P. I think you just have T in the wrong place, but be sure to read the very bottom of my answer regarding clip-space. \$\endgroup\$ – Jon Mar 28 '16 at 0:47
1
\$\begingroup\$

There are a few things going on. This is probably important to know, even if you never use GL.


These aren't the same anywhere, anytime:

"translationMatrix * rotationMatrix * scalingMatrix" //translate then rotate then scale
"scalingMatrix * rotationMatrix * translationMatrix" //scale then rotate then translate

On top of that:

GL is like an RPN-calculator using the last value provided, first (post-multiply):

 translationMatrix * rotationMatrix * scalingMatrix ==
"scalingMatrix * rotationMatrix * translationMatrix" //scale then rotate then translate

[R2] translationMatrix
[R1] rotationMatrix
[R0] scalingMatrix
[op] * //(replaces scaling and rotation matrices with (scalingMatrix, then rotationMatrix)
[op] * //(replaces [result] with ([result], then translationMatrix)

DX is like a "normal" calculator (pre-multiply):

 scalingMatrix *  rotationMatrix  * translationMatrix ==
"scalingMatrix *  rotationMatrix  * translationMatrix" ==
(scalingMatrix * (rotationMatrix) * translationMatrix) //() wherever you want

     scalingMatrix * rotationMatrix    = [immediate result] //scale, then rotate
[immediate result] * translationMatrix = [immediate result] //then translate

Both are correct for their respective API's and both produce the same results:

scaling then rotation then translation

I'm not an oracle, but all of my DX code looks like this (although I use the built-in matrix methods??):

world = scale * rotation * translation;
viewProj = view * proj;
//HLSL defaults to column-major but DX is row-major, so Transpose()
//(or don't use the defaults)
SendToGPU(world.Transpose());
SendToGPU(viewProj.Transpose()); 

//in the shader
worldPosition = vertex * world * viewProj;
"worldPosition = vertex then S then R then T then V then P"

You can step through this in the debugger with known input. Right after you create your world matrix, transform Vector3.Up by it and breakpoint. If you translate to {0,1,0} then scale by 2.0, you should be at {0,2,0}. If you end up at {0,1,0}, you are scaling, then translating.


Don't work so hard:

Generally, we try to re-use geometry. If you create a quad, centered at {0,0,0} whose length and width equal 1.0, then you can easily ModelMatrix that one quad to any size and place you want (including full screen). Using Identity for the MVP, you draw directly in clip-space, which centers a quad constructed as such in the screen by default. Clip-space has a fixed range of -1 to 1 on all axes (length/width/height == 2), so you could just scale the unit-quad by 2 and forget all the camera stuff.

\$\endgroup\$
  • \$\begingroup\$ thanks for elaborate explanantion. However i can draw using the clip space but i should have been a bit more clearer in my question. What i am trying to achieve is to draw a quad/triangle using screen co-ordinates so that i can place exactly where i want without the need to calculate the vertices vertices all the time when ever i wish to place my quad/triangle. Having read your explanation and understand things better, i have tried your your recommendation, i am now able to render my quad/triangle exactly where i would like to place. \$\endgroup\$ – Dave23Rave Mar 28 '16 at 10:59

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.