Resizing orthographic camera while zoomed in

Started by
6 comments, last by dave09cbank 7 years, 11 months ago

Hi Folks,

I have a orthographic camera. With the help of this camera i'm able to render a quad onto the screen using screen-cordinates.

Using the camera i perform the zoom in/out on specific mouse position which is based on the pseudocode from http://www.gamedev.net/topic/541443-zoom-about-cursor-position/ post which all seems to work fine as expected.

Now the trouble i'm having is to resize the orthographic camera when the window size changes while i'm zoomed in.

Part of this issue is my quad now renders on the entire screen rather than the co-ordinates i specify.

If i now click on the window area then my quad is rendered correctly within the co-ordinates that I specify on window resize with the texture but i still see the texture image that was rendered on the entire screen before the quad is rendered on the appropriate co-ordinates..

If i'm completely zoomed out then resizing is fine and works as expected.

Any suggestions ?

If any code is required then do let me know as I'm happy to upload it here.

Thanks.

EDIT:

Code used for projection matrix:


                     
            // Prepare ViewProjection matrices
            // Create the view matrix from our camera position, look target and up direction direct X uses left hand co-ordinate system
            m_projectionMatrix = Matrix.OrthoOffCenterLH(0, (float)m_displaySize.Width, (float)m_displaySize.Height, 0, 0f, 100.0f);

            m_viewProjectionMatrix = m_viewMatrix * m_projectionMatrix;
            m_perObject.ViewProjection = m_viewProjectionMatrix;

            // perform the Transpose of the matrices
            m_perObject.Transpose();

Screenshots:

Screenshot 1: Normal display:

[attachment=31658:Normal.JPG]

Screenshot 2: No zoom resize

[attachment=31657:Normal resize.JPG]

Screenshot 3: Zoomed in

[attachment=31659:Zoomed in.JPG]

Screenshot 4: Error when zoomed in but resized

[attachment=31656:Error when zoomed.JPG]

Screenshot 5: Invalid display when zoomed but when performing zoom again on mouse click

[attachment=31655:Error when zoomed after mouse click.JPG]

Advertisement

Now the trouble i'm having is to resize the orthographic camera when the window size changes while i'm zoomed in.

Part of this issue is my quad now renders on the entire screen rather than the co-ordinates i specify.

If i now click on the window area then my quad is rendered correctly within the co-ordinates that I specify on window resize with the texture but i still see the texture image that was rendered on the entire screen before the quad is rendered on the appropriate co-ordinates..

If i'm completely zoomed out then resizing is fine and works as expected.

A few screenshots might help explain your problem a bit better. This sounds like an issue clearing the backbuffer/invalidating the window. It sounds like only the original window area is being updated, try checking for things like scissor rects/viewports.

Are you rebuilding your projection matrix when the window resizes as it sounds like calling that section of code solves the problem. I recall your previous thread and the suggestion I made should work when you resize the window:


// going to zoom in 200%
float zoom = 2; // 200%
float xPos = ...
float yPos = ...
float left = -m_displaySize.Width/(2*zoom) + xPos;
float right = m_displaySize.Width/(2*zoom) + xPos;
float top = -m_displaySize.Height/(2*zoom) + yPos;
float bottom = m_displaySize.Height/(2*zoom) + yPos;
m_projectionMatrix = Matrix.OrthoOffCenterLH(left, right, bottom, top, 0f, 100.0f);

You would have to store that x/y position and rebuild using the previous known values for them when the window resizes.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

Thanks for the reply @Nanoha.

Your reply to my previous posts have been really helpful in learning and understanding directx.

I've been setting up my projection matrix as suggested by yourself in previous post.

I have posted some screenshot and code i use to setup my projection matrix as requested. In screenshot 5 you will see there some text in white above the text 04/2016 which is from the previous. I will try to provide a more better screenshot tomorrow when its bright outside.

Also, i setup my set my viewport to be the same size as my entire window.

Also i have tried clearing the backbuffer aswell but had no luck and i'm not using any scissor rects.

If there is anymore information required then do let me know as i hope above should be able to provide you more better understanding as what is going wrong and what i could be doing wrong.

Thanks.

Could you post the code that is taking account of the zoom and also the part where you build the view matrix.

Some suggestions that might help you figure out the problem:

Hard code the interactions, i.e. you always 'click' the exact same place each time and zoom the exact same amount. That'll help reduce the amount of variables at play.

It might be helpful to try and use some type of checkboard image instead of the camera feed too, that should help figure out what's going on where you have an image behind as in picture 5 where there is that slight bit of extra text. With a checkboard type image instead you can see if that back image is of the previous magnification or the new magnification etc.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

@Nanoha iv updated my screenshots with checkboard image.

I setup my view matrix as below:



            m_viewMatrix = Matrix.LookAtLH(Vector3.Zero, Vector3.UnitZ, Vector3.UnitY);

Under normal circumstances when my quad is rendered correctly without any zoom performed on it, zoom in/out is performed using the code below:


 var wvpInvertedMatrix = m_perObject.World * m_perObject.ViewProjection;
            wvpInvertedMatrix = Matrix.Invert(wvpInvertedMatrix);

            // get the mouse position in world units from screen units
            var transformedCordinates = Vector3.TransformCoordinate(new Vector3(iMousePosX, iMousePosY, 0), wvpInvertedMatrix); 

            var midPtY = this.m_displaySize.Height / 2;
            var midPtX = this.m_displaySize.Width / 2;
            var mousePosDiffX = (midPtX - iMousePosX);
            var mousePosDiffY = (midPtY - iMousePosY);

            // previously selected a mouse so we calculate how much to move the by
            var deltaZ = transformedCordinates.Z - m_lastZPos;
            var deltaY = deltaZ * MOVE_FACTOR * mousePosDiffY;
            var deltaX = deltaZ * MOVE_FACTOR * mousePosDiffX;

            m_viewMatrix.TranslationVector += new Vector3((float)deltaX, (float)deltaY, 0);

            // only when zooming out
            //check if additional  deltaX and deltaY to be added as we could have zoomed in two different positions
            if (!bZoomIn)
            {
                // we add additional 1 as we receive zoom depth of 0 when completely zooming out 
                // so that we are not dividing by zero which gives us infinite value
                var zoomDepth = (iZoomDepth + 1);
                var tansVecor = m_viewMatrix.TranslationVector;
                var calculatedX = deltaX * zoomDepth;
                var calculatedY = deltaY * zoomDepth;
                var additionaDeltaX = tansVecor.X + (float)calculatedX;
                var additionalDeltaY = tansVecor.Y + (float)calculatedY;

                // split equally based on zoom depth
                additionaDeltaX = additionaDeltaX / zoomDepth;
                additionalDeltaY = additionalDeltaY / zoomDepth;

                //System.Diagnostics.Debug.WriteLine($"Delta ({deltaX}, {deltaY}, {deltaZ}) -- Mouse Pos({iMousePosX}, {iMousePosY}) ---[{tansVecor.X}, {tansVecor.Y}] ==== ({resX}, {resY})");

                m_viewMatrix.TranslationVector -= new Vector3((float)additionaDeltaX, (float)additionalDeltaY, 0);
            }

            m_lastZPos = transformedCordinates.Z;

m_viewProjectionMatrix = m_viewMatrix * m_projectionMatrix;
                m_perObject.ViewProjection = m_viewProjectionMatrix;
                m_perObject.Transpose();

                m_iLastZoomDepth = iZoomDepth;

                // above we move the image in x & y so keep the point under mouse
                // for zooming 
                 var projectVector = Vector3.Zero;
            projectVector.Z = m_iLastZoomDepth * MOVE_FACTOR;

            m_perObject.ViewProjection.TranslationVector -= projectVector;

                // store the translation vector as this will be used during the resize
                m_ptzOffsetVector = m_viewMatrix.TranslationVector;
                m_lastMousePos.X = iMousePosX;
                m_lastMousePos.Y = iMousePosY;

Move Factor:


const float MOVE_FACTOR = 0.005f;

What i have also noticed is if i resize when zoom then i can't seem maintain the same area of texture that was being rendered within the quad. it seems to change enlarge/shrink based on the resize window size. This doesn't occur if i'm not zoomed in.

Screenshot 5 looks odd, that does suggest a viewport type issue.

Are screenshot 1 and 2 correct or should the quad in screenshot 2 have be the same size but clipped?

How does a user interact with this? How do they make it zoom, do they drag the view around to move or do they click?

I can't really say what the exact problem is as it's probably a combination of things probably all spread out. I would approach this by trying to boil it all down to having 3 basic values, the zoom level (1x, 2x, etc) and an x/y position which you want to put at the centre of the window. Then I'd make a method that uses just those 3 values and the display size and builds both a projection matrix and a view matrix from it. Those are probably all you need to do it, you can probably get away without a view matrix too as the orthogonal projection can store that quite easily. It's probably more efficient to use only the projection matrix since you are just using 2D.

If any of the values change, such as the screensize, or the magnification or the positions then just call that method which will correctly build your projection. I am not familiar with DirectX but when your display size changes you may need to update the viewport or similar too.

How you update those values depends on how the user interacts so I can't say much but you are definitely on the right track where you convert window space to world space values as doing that makes life much easier.

I think your current solution is more complicated than it needs to be but I certainly don't have as good an overview of your project as you do.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

Thanks for the reply.

My viewport is set to be the size of the screen/window which is the same size i initialize my projection matrix with.

Yes screenshot 1 and 2 are correct. As i have re-sized the window so the quad is re-sized still displaying the entire texture/image inside it.

For zooming user can click anywhere and then hold the mouse down on the checkboard image which is the quad. For zoomin in on a position i update the Z factor and move the view matrix (x and y).

Yes, i can confirm my viewport gets updated whenever my screen size changes.

In addition to above,

  1. if i re-initialise my ortho camera without trying to preserve the zoom state and position of the view, my quad render correctly.
  2. Another option i tried was to render zoom and then on resize i stop rendering my quad. As a result i still see a partial checkboard image even though i clear my render target view and depth stencil.
  3. Finally what i ahve tried is not change the view matrix on the resize and keep it as it is and just update the projection matrix. Now doing so it renders the image as if the orthographic camera has been created from scratch but quad is at the wrong location. Now if i click then view gets updated and the quad is placed at the correct location and of size but i still see option 2. Not sure what is going on though but will have to probably dig deep to find out as to what is going on.

Again my application is video player which gives you ability to perform zoom int/out on a specific mouse position.

thanks.

Upon further investigating and messing around I found that it turns to be some what timing issue which is what i think

What i did was i zoomed in then on re-sizing while i'm zoomed in if i stop rendering my quad for 2 seconds and clear the render target view , then after 2-seconds has elapsed my quad is rendered correctly and as expected.

Could anyone tell me as to why this happen or this works or if my conclusion about timing is still a guess ?

Thanks.

This topic is closed to new replies.

Advertisement