grknight
asked on
3d zoom fit (directX, perspective) implementation needs direction
I am creating a zoom fit function for a 3d model. Using DirectX 9, VB.NET (C# and C++ OK), right hand coord system, and perspective view. I have reviewed
http://www4.experts-exchange.com/questions/21903389/Zoom-to-fit-function-implementation-problem.html
but still have some problems.
Basically, I need some direction (psuedocode) on an overall approach. The above post was for ortho projections, and did not seem to work completely in my case. Currently, I can transform all my world space vertices to screen space using Vector3.TransformCoordinat e(vertex(i ),matView* matProj). This gives me a cloud of screen points, some of which are outside the current screen display (-1 to 1 in x and y directions). Next, I calculate the world space coordinate of the center of a 2D screen bounding box (bb) containing all the transformed points using Vector3.TransformCoordinat e(bb_cente r,Inverse( matView*ma tProj)), and move my camera target to that world space location, while also moving the camera position the same relative amount to preserve the camera look direction. The effectivly "centers" the model, but I still need to determine how to adjust distance between camera position and camera target to effectivly zoom in/out such that the bound box of transformed points fills the viewable screen area.
Some issues are:
1. first, the camera centering I described works great in ortho mode, after which I can manually zoom in/out as necessary until the model is completely within the screen. In perspective mode, manually zooming does not end up with a model that fits the screen edge to edge. Probably because as the camera position changes, so does the matView matrix, which would change all my transformed screen verticies.
2. how to move the camera to do the zoom in/out automatically such that the model fits the screen
I would prefer not to have to do an itterative method for camera fitting which some have suggested.
There is little to no examples of this on the web, but if you find one, let me know!
Public Const FOV As Single = Math.PI / 4
Public Const NEARCLIP As Single = 1
Public Const FARCLIP As Single = 100000
matProj = Matrix.PerspectiveFieldOfV iewRightHa nded(FOV, AspectRatio, NEARCLIP, FARCLIP)
matView = Matrix.LookAtRightHanded(C ameraPosit ion, CameraTarget, CameraUp)
http://www4.experts-exchange.com/questions/21903389/Zoom-to-fit-function-implementation-problem.html
but still have some problems.
Basically, I need some direction (psuedocode) on an overall approach. The above post was for ortho projections, and did not seem to work completely in my case. Currently, I can transform all my world space vertices to screen space using Vector3.TransformCoordinat
Some issues are:
1. first, the camera centering I described works great in ortho mode, after which I can manually zoom in/out as necessary until the model is completely within the screen. In perspective mode, manually zooming does not end up with a model that fits the screen edge to edge. Probably because as the camera position changes, so does the matView matrix, which would change all my transformed screen verticies.
2. how to move the camera to do the zoom in/out automatically such that the model fits the screen
I would prefer not to have to do an itterative method for camera fitting which some have suggested.
There is little to no examples of this on the web, but if you find one, let me know!
Public Const FOV As Single = Math.PI / 4
Public Const NEARCLIP As Single = 1
Public Const FARCLIP As Single = 100000
matProj = Matrix.PerspectiveFieldOfV
matView = Matrix.LookAtRightHanded(C
ASKER
I don't believe the perspective matrix needs to change, as that would basically change the viewing fustrum. I need to know how to calculate the new camera position and target (effectivly the view matrix) to fit the model to the screen.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I did some testing and here are the results. First, moving the projection plane (near clip) distance does not cause any zooming effect, although changing the FOV in the projection matrix does. However, I don't want to change the projection matrix since that would cause problems as the user continued to rotate/pan the model after the zoom fit operation. Kinda like using the zoom on your camera,and then trying to navigate around your subject by just looking through the lens of a zoomed camera. Tunnel vision.
Ultimately, I went with an iterative method that consists of calculating the bounding box of the model, transforming the box's corners to screen space and comparing with the current screen extents. If they were outside the screen extents, I move the camera away from the model some fraction and then (because of perspective view) transform the box points again, move the camera in/out, etc... via a loop. See the code below.
Dim boundingPoints As New System.Collections.Generic .List(Of Vector3)
Dim ProjBounds As New Bounds
Dim BoundingBox As New BoundingBox
BoundingBox.CreateFromVisi bleObjects () 'create the bounding box from the model
BoundingBox.BoxPoints(boun dingPoints ) 'get the box corner points (world space) and load into the array boundingPoints
'Itterative Fit Procedure
Dim ScreenBounds As New Bounds
ScreenBounds.minX = -1
ScreenBounds.maxX = 1
ScreenBounds.minY = -1
ScreenBounds.maxY = 1
Dim relaxationFactor As Single = 0.25
Dim Itt As Integer = 0
Dim dx As Single = 0
Dim dy As Single = 0
Do While Not ApproxEqual(Math.Max(dx, dy), 1, 0.01) AndAlso Itt < 50
'//CAMERA POSITION
Canvas.UpdateViewProjMatri ces(TrackB all.CamPos ition, TrackBall.CamTarget)
Canvas.TransformAllCoordin ates(bound ingPoints, ProjBounds) 'projBounds is a 2D rectangle in screen space around our transformed boundingPoints
Dim ProjCenterInWorldSpace As Vector3 = Vector3.TransformCoordinat e(ProjBoun ds.CenterP oint, _
Matrix.Invert(Matrix.Multi ply(Canvas .matView, Canvas.matProj)))
'move the camera target toward this point
Dim CamTargettoProjCenterWS As Vector3 = Vector3.Subtract(ProjCente rInWorldSp ace, TrackBall.CamTarget)
TrackBall.CamPosition += CamTargettoProjCenterWS * relaxationFactor
TrackBall.CamTarget += CamTargettoProjCenterWS * relaxationFactor
'//======================= ========== ========== ====
'//CAMERA ZOOM====================== ========== ====
Canvas.UpdateViewProjMatri ces(TrackB all.CamPos ition, TrackBall.CamTarget)
Canvas.TransformAllCoordin ates(bound ingPoints, ProjBounds)
'adjust camera zoom
dx = ProjBounds.deltaX / ScreenBounds.deltaX
dy = ProjBounds.deltaY / ScreenBounds.deltaY
If dx < 1 AndAlso dy < 1 Then
'camera must move toward model
'CamDirection is the un-normalized vector from cam position to cam target
TrackBall.CamPosition += TrackBall.CamDirection * (1 - Math.Max(dx, dy)) * relaxationFactor
ElseIf dx > 1 OrElse dy > 1 Then
'camera must move away from model
TrackBall.CamPosition += TrackBall.CamDirection * (1 - Math.Max(dx, dy)) * relaxationFactor
End If
'//======================= ========== ========== ====
#If DEBUG Then
frmMain.cfbCommandLine.Add Message("F it: " & Math.Max(dx, dy).ToString("F4") & " Itt: " & Itt.ToString)
Application.DoEvents()
'TrackBall.Update()
'System.Threading.Thread.S leep(50)
#End If
Itt += 1
Loop
Canvas.ReDraw()
Ultimately, I went with an iterative method that consists of calculating the bounding box of the model, transforming the box's corners to screen space and comparing with the current screen extents. If they were outside the screen extents, I move the camera away from the model some fraction and then (because of perspective view) transform the box points again, move the camera in/out, etc... via a loop. See the code below.
Dim boundingPoints As New System.Collections.Generic
Dim ProjBounds As New Bounds
Dim BoundingBox As New BoundingBox
BoundingBox.CreateFromVisi
BoundingBox.BoxPoints(boun
'Itterative Fit Procedure
Dim ScreenBounds As New Bounds
ScreenBounds.minX = -1
ScreenBounds.maxX = 1
ScreenBounds.minY = -1
ScreenBounds.maxY = 1
Dim relaxationFactor As Single = 0.25
Dim Itt As Integer = 0
Dim dx As Single = 0
Dim dy As Single = 0
Do While Not ApproxEqual(Math.Max(dx, dy), 1, 0.01) AndAlso Itt < 50
'//CAMERA POSITION
Canvas.UpdateViewProjMatri
Canvas.TransformAllCoordin
Dim ProjCenterInWorldSpace As Vector3 = Vector3.TransformCoordinat
Matrix.Invert(Matrix.Multi
'move the camera target toward this point
Dim CamTargettoProjCenterWS As Vector3 = Vector3.Subtract(ProjCente
TrackBall.CamPosition += CamTargettoProjCenterWS * relaxationFactor
TrackBall.CamTarget += CamTargettoProjCenterWS * relaxationFactor
'//=======================
'//CAMERA ZOOM======================
Canvas.UpdateViewProjMatri
Canvas.TransformAllCoordin
'adjust camera zoom
dx = ProjBounds.deltaX / ScreenBounds.deltaX
dy = ProjBounds.deltaY / ScreenBounds.deltaY
If dx < 1 AndAlso dy < 1 Then
'camera must move toward model
'CamDirection is the un-normalized vector from cam position to cam target
TrackBall.CamPosition += TrackBall.CamDirection * (1 - Math.Max(dx, dy)) * relaxationFactor
ElseIf dx > 1 OrElse dy > 1 Then
'camera must move away from model
TrackBall.CamPosition += TrackBall.CamDirection * (1 - Math.Max(dx, dy)) * relaxationFactor
End If
'//=======================
#If DEBUG Then
frmMain.cfbCommandLine.Add
Application.DoEvents()
'TrackBall.Update()
'System.Threading.Thread.S
#End If
Itt += 1
Loop
Canvas.ReDraw()
Congratulations.
And thanks for sharing your result with all of us.
Jose
And thanks for sharing your result with all of us.
Jose
Zoom implics in fixed camera. Just the focal lens changes.
If the camera moves, it is a travelling (move) or panning (rotating around a vertical axis) or tilting (rotation around the viewing ray).
I understand you need to inverse calculate the perspective projection size to make its zoom to fit the screen.
Is it your understanding too?
Jose