Code archives/3D Graphics - Effects/Dolly-Zoom effect
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
Included are three possible ways to perform this zoom effect. They all consist on mostly the same: - Store the original distance from the camera to the subject. - Move the camera by a small amount. - Update the camera's zoom to preserve the screen size of the subject based on the ratio (CurrentDistance / OriginalDistance). - The screen size of the subject remains the same, but the perspective changes and that's what gives the effect. The Distance method is best suited if you're working with Blitz3D. The FOV (field-of-view) method is best suited for other game engines where you change a camera's zoom based on this property alone. Original thread: http://blitzbasic.com/Community/posts.php?topic=99719 | |||||
;************************************************** ; ; 3 Recipes for the Dolly-Zoom effect ; (also known as Push-Pull or Vertigo zoom). ; ; Demo and Distance-Zoom method by Floyd. ; Adaptation, FOV and Z-Scale methods by Kryzon. ; ; ---------------------------------------------- ; Press SPACE to change the zoom method. ; Hold A or Z to move the camera. ; ; Jan 6th 2013 ; ;************************************************** ;Zoom methods: ;1 - Distance-Zoom ;2 - FOV ;3 - Z-Scale (messes up the lighting, here only for "academic" purposes.) Local dollyMethod% = 1 AppTitle "Dolly-Zoom effect demo" Graphics3D 800, 600, 0, 2 SetBuffer BackBuffer() HidePointer Local sphere% = CreateSphere() Local camera% = CreateCamera() : PositionEntity camera, 0, 5, -5 CameraRange camera, 0.5, 1000 : PointEntity camera, sphere TurnEntity CreateLight(), 30, 70, 0 VariousOtherThings 30 ;Setup for Distance-Zoom method: Local zoom_over_distance# = 1.0 / EntityDistance( camera, sphere ) ; CameraZoom is 1.0 ;Setup for FOV method: Local subjectDistance# = EntityDistance( camera, sphere ) Local originalFOV# = 90.0 ;In Blitz3D, the equivalent of a CameraZoom of 1.0 Local originalTan# = Tan(originalFOV / 2.0) Local currentFOV# = 90.0 Local distanceRatio# = 1.0 ;Setup for Z-Scale method: subjectDistance# = EntityDistance( camera, sphere) Local cameraScale# = 1.0 distanceRatio# = 1.0 ;Main Loop. While Not KeyDown(1) ;Move the camera. z# = EntityZ( camera ) If KeyDown(44) Then z = z * 1.01 If KeyDown(30) Then z = z / 1.01 PositionEntity camera, 0, -z, z ;Select a zoom method. If KeyHit(57) Then dollyMethod = dollyMethod + 1 If dollyMethod > 3 Then dollyMethod = 1 If dollyMethod <> 3 Then ScaleEntity camera, 1.0, 1.0, 1.0 Else CameraZoom camera, 1.0 EndIf EndIf Select dollyMethod Case 1 ;Distance-Zoom CameraZoom camera, zoom_over_distance * EntityDistance( camera, sphere ) PointEntity camera, sphere RenderWorld Text 10, 10, "Method: Distance-Zoom" Text 10, 30, "Distance = " + EntityDistance( camera, sphere ) Text 10, 50, "CameraZoom = " + zoom_over_distance * EntityDistance( camera, sphere ) Case 2 ;FOV distanceRatio# = subjectDistance / EntityDistance( camera, sphere ) ;The FOV (field-of-view) is an angle value that several engines use for setting up a camera's zoom. currentFOV = 2.0 * ATan(distanceRatio * originalTan) ;You apply that FOV angle in whatever way your engine does it (matrix, function, etc.). In case of Blitz3D... CameraZoom camera, ( 1.0 / Tan(currentFOV/2.0) ) PointEntity camera, sphere RenderWorld Text 10, 10, "Method: FOV" Text 10, 30, "Distance = " + EntityDistance( camera, sphere ) Text 10, 50, "CameraZoom = " + (1.0 / Tan(currentFOV/2.0 )) + " ("+currentFOV+" degrees)" Case 3 ;Z-Scale distanceRatio# = subjectDistance / EntityDistance( camera, sphere ) ScaleEntity( camera, 1.0, 1.0, (1.0 / distanceRatio) ) RenderWorld Text 10, 10, "Method: Z-Scale" Text 10, 30, "Distance = " + EntityDistance( camera, sphere ) Text 10, 50, "CameraZoom = " + ( 1.0 / distanceRatio ) End Select Flip Wend ;Aesthetics. Function VariousOtherThings( quantity ) For n = 1 To quantity Select Rand( 1, 4 ) Case 1 : temp = CreateSphere() Case 2 : temp = CreateCone() Case 3 : temp = CreateCylinder() Case 4 : temp = CreateCube() End Select ScaleEntity temp, Rnd( 0.6, 1.5 ), Rnd( 0.6, 1.5 ), Rnd( 0.6, 1.5 ) EntityColor temp, Rand( 100, 255 ), Rand( 100, 255 ), Rand( 100, 255 ) RotateEntity temp, Rnd( -20, 20 ), Rnd( -50, 50 ), Rnd( -20, 20 ) angle# = Rnd( -45, 225) dist# = Rnd( 2.5, 6 ) PositionEntity temp, dist * Cos( angle ), Rnd( - 3, 3 ), dist * Sin( angle ) Next End Function End |
Comments
| ||
This is great, was pondering/wondering how to go about achieving this very thing - thanks for the post. |
| ||
Just curious as to the actual effect of the z scale parameter with respect to a camera entity here: ScaleEntity( camera, 1.0, 1.0, (1.0 / distanceRatio) ) |
| ||
Hi _PJ_, sorry for the delay! I'm not sure of the internals, but what I think is happening is you're transforming the camera's matrix. Internally, when you're going to render a mesh, you need to transform it in relation to the camera (something called Model View), and since this Model View was transformed itself (when we scale the camera), everything will appear different. The Model View's scale is always the default [1,1,1], and when you change it in any way you're going to have some out-worldly result. That's why lighting seems to change: it is a mesh's vertices' positions (after being transformed by the Model View) that are used to calculate lighting. This phenomenon is only happening "visually". "Logically", all entity positions, vertices, scales, collisions etc. remain the same. So if you scale your camera in the middle of your game nothing logical-wise should change, only visually. |
Code Archives Forum