@@ -240,6 +240,7 @@ pub struct Camera {
240240 projection_type : ProjectionType ,
241241 z_near : f32 ,
242242 z_far : f32 ,
243+ zoom_relative_depth : bool ,
243244 position : Vec3 ,
244245 target : Vec3 ,
245246 up : Vec3 ,
@@ -259,10 +260,11 @@ impl Camera {
259260 height : f32 ,
260261 z_near : f32 ,
261262 z_far : f32 ,
263+ zoom_relative_depth : bool ,
262264 ) -> Self {
263265 let mut camera = Camera :: new ( viewport) ;
264266 camera. set_view ( position, target, up) ;
265- camera. set_orthographic_projection ( height, z_near, z_far) ;
267+ camera. set_orthographic_projection ( height, z_near, z_far, zoom_relative_depth ) ;
266268 camera
267269 }
268270
@@ -277,15 +279,17 @@ impl Camera {
277279 field_of_view_y : impl Into < Radians > ,
278280 z_near : f32 ,
279281 z_far : f32 ,
282+ zoom_relative_depth : bool ,
280283 ) -> Self {
281284 let mut camera = Camera :: new ( viewport) ;
282285 camera. set_view ( position, target, up) ;
283- camera. set_perspective_projection ( field_of_view_y, z_near, z_far) ;
286+ camera. set_perspective_projection ( field_of_view_y, z_near, z_far, zoom_relative_depth ) ;
284287 camera
285288 }
286289
287290 ///
288291 /// New camera which projects the world with a general planar projection.
292+ /// This is best used with the relative depth unit if zooming is allowed.
289293 ///
290294 pub fn new_planar (
291295 viewport : Viewport ,
@@ -295,10 +299,11 @@ impl Camera {
295299 field_of_view_y : impl Into < Radians > ,
296300 z_near : f32 ,
297301 z_far : f32 ,
302+ zoom_relative_depth : bool ,
298303 ) -> Self {
299304 let mut camera = Camera :: new ( viewport) ;
300305 camera. set_view ( position, target, up) ;
301- camera. set_planar_projection ( field_of_view_y, z_near, z_far) ;
306+ camera. set_planar_projection ( field_of_view_y, z_near, z_far, zoom_relative_depth ) ;
302307 camera
303308 }
304309
@@ -308,13 +313,20 @@ impl Camera {
308313 pub fn set_perspective_projection (
309314 & mut self ,
310315 field_of_view_y : impl Into < Radians > ,
311- z_near : f32 ,
312- z_far : f32 ,
316+ mut z_near : f32 ,
317+ mut z_far : f32 ,
318+ zoom_relative_depth : bool ,
313319 ) {
314320 self . z_near = z_near;
315321 self . z_far = z_far;
322+ self . zoom_relative_depth = zoom_relative_depth;
316323 let field_of_view_y = field_of_view_y. into ( ) ;
317324 self . projection_type = ProjectionType :: Perspective { field_of_view_y } ;
325+ if zoom_relative_depth {
326+ let zoom = self . position . distance ( self . target ) ;
327+ z_near *= zoom;
328+ z_far *= zoom;
329+ }
318330 self . projection =
319331 cgmath:: perspective ( field_of_view_y, self . viewport . aspect ( ) , z_near, z_far) ;
320332 }
@@ -326,13 +338,24 @@ impl Camera {
326338 /// The view frustum depth is `z_near` to `z_far`.
327339 /// All of the above values are scaled by the zoom factor which is one over the distance between the camera position and target.
328340 ///
329- pub fn set_orthographic_projection ( & mut self , height : f32 , z_near : f32 , z_far : f32 ) {
341+ pub fn set_orthographic_projection (
342+ & mut self ,
343+ height : f32 ,
344+ mut z_near : f32 ,
345+ mut z_far : f32 ,
346+ zoom_relative_depth : bool ,
347+ ) {
330348 self . projection_type = ProjectionType :: Orthographic { height } ;
331349 self . z_near = z_near;
332350 self . z_far = z_far;
351+ self . zoom_relative_depth = zoom_relative_depth;
333352 let zoom = self . position . distance ( self . target ) ;
334353 let height = zoom * height;
335354 let width = height * self . viewport . aspect ( ) ;
355+ if zoom_relative_depth {
356+ z_near *= zoom;
357+ z_far *= zoom;
358+ }
336359 self . projection = cgmath:: ortho (
337360 -0.5 * width,
338361 0.5 * width,
@@ -345,35 +368,33 @@ impl Camera {
345368
346369 ///
347370 /// Specify the camera to use planar projection with the given field of view in the y-direction and near and far plane.
348- /// This can be either a planar or perspective projection depending on the field of view provided, which is permitted to be zero or negative.
371+ /// This can be either an orthographic or perspective projection depending on the field of view provided, which is permitted to be zero or negative.
372+ /// This is best used with the relative depth unit if zooming is allowed.
349373 ///
350374 pub fn set_planar_projection (
351375 & mut self ,
352376 field_of_view_y : impl Into < Radians > ,
353377 mut z_near : f32 ,
354378 mut z_far : f32 ,
379+ zoom_relative_depth : bool ,
355380 ) {
356381 self . z_near = z_near;
357382 self . z_far = z_far;
383+ self . zoom_relative_depth = zoom_relative_depth;
358384 let field_of_view_y = field_of_view_y. into ( ) ;
359385 self . projection_type = ProjectionType :: Planar { field_of_view_y } ;
360386 let depth = self . position . distance ( self . target ) ;
361387 let height = 2.0 * depth;
362- let focal = -Rad :: cot ( field_of_view_y / 2.0 ) * depth;
363- z_near -= depth;
364- z_far -= depth;
365- // Required to ensure near/far plane does not cross focal point when at close zoom levels
366- if focal < 0.0 && z_near < focal {
367- z_near = focal + 0.001 ;
368- } else if focal > 0.0 && z_far > focal {
369- z_far = focal - 0.001 ;
388+ if zoom_relative_depth {
389+ z_near *= depth;
390+ z_far *= depth;
370391 }
371392 self . projection = planar (
372393 field_of_view_y,
373394 self . viewport . aspect ( ) ,
374395 height,
375- z_near,
376- z_far,
396+ z_near - depth ,
397+ z_far - depth ,
377398 ) * Mat4 :: from_translation ( vec3 ( 0.0 , 0.0 , depth) ) ;
378399 }
379400
@@ -386,13 +407,28 @@ impl Camera {
386407 self . viewport = viewport;
387408 match self . projection_type {
388409 ProjectionType :: Orthographic { height } => {
389- self . set_orthographic_projection ( height, self . z_near , self . z_far ) ;
410+ self . set_orthographic_projection (
411+ height,
412+ self . z_near ,
413+ self . z_far ,
414+ self . zoom_relative_depth ,
415+ ) ;
390416 }
391417 ProjectionType :: Perspective { field_of_view_y } => {
392- self . set_perspective_projection ( field_of_view_y, self . z_near , self . z_far ) ;
418+ self . set_perspective_projection (
419+ field_of_view_y,
420+ self . z_near ,
421+ self . z_far ,
422+ self . zoom_relative_depth ,
423+ ) ;
393424 }
394425 ProjectionType :: Planar { field_of_view_y } => {
395- self . set_planar_projection ( field_of_view_y, self . z_near , self . z_far ) ;
426+ self . set_planar_projection (
427+ field_of_view_y,
428+ self . z_near ,
429+ self . z_far ,
430+ self . zoom_relative_depth ,
431+ ) ;
396432 }
397433 }
398434 true
@@ -415,13 +451,28 @@ impl Camera {
415451 self . up ,
416452 ) ;
417453 match self . projection_type {
418- ProjectionType :: Orthographic { height } => {
419- self . set_orthographic_projection ( height, self . z_near , self . z_far )
420- }
421- ProjectionType :: Planar { field_of_view_y } => {
422- self . set_planar_projection ( field_of_view_y, self . z_near , self . z_far )
454+ ProjectionType :: Perspective { field_of_view_y } => {
455+ if self . zoom_relative_depth {
456+ self . set_perspective_projection (
457+ field_of_view_y,
458+ self . z_near ,
459+ self . z_far ,
460+ self . zoom_relative_depth ,
461+ ) ;
462+ }
423463 }
424- _ => { }
464+ ProjectionType :: Orthographic { height } => self . set_orthographic_projection (
465+ height,
466+ self . z_near ,
467+ self . z_far ,
468+ self . zoom_relative_depth ,
469+ ) ,
470+ ProjectionType :: Planar { field_of_view_y } => self . set_planar_projection (
471+ field_of_view_y,
472+ self . z_near ,
473+ self . z_far ,
474+ self . zoom_relative_depth ,
475+ ) ,
425476 } ;
426477 }
427478
@@ -578,6 +629,13 @@ impl Camera {
578629 self . z_far
579630 }
580631
632+ ///
633+ /// Returns if the near and far planes are calculated relative to the current zoom level.
634+ ///
635+ pub fn zoom_relative_depth ( & self ) -> bool {
636+ self . zoom_relative_depth
637+ }
638+
581639 ///
582640 /// Returns the position of this camera.
583641 ///
@@ -627,6 +685,7 @@ impl Camera {
627685 projection_type : ProjectionType :: Orthographic { height : 1.0 } ,
628686 z_near : 0.0 ,
629687 z_far : 0.0 ,
688+ zoom_relative_depth : false ,
630689 position : vec3 ( 0.0 , 0.0 , 5.0 ) ,
631690 target : vec3 ( 0.0 , 0.0 , 0.0 ) ,
632691 up : vec3 ( 0.0 , 1.0 , 0.0 ) ,
0 commit comments