POV-Ray : Newsgroups : povray.general : Bug: Fisheye and Omnimax camera do not handle camera aspect ratio Server Time
7 Aug 2024 17:22:38 EDT (-0400)
  Bug: Fisheye and Omnimax camera do not handle camera aspect ratio (Message 1 to 1 of 1)  
From: Greg Smith
Subject: Bug: Fisheye and Omnimax camera do not handle camera aspect ratio
Date: 16 Jul 2001 19:52:32
Message: <3B537E2B.DBA9B729@alumni.uwaterloo.ca>
Bug: Fisheye and Omnimax camera do not handle camera aspect ratio.

My Machine:
POV Version 3.1g.watcom.win32
Under Win2000, on a P4, with 256 MB Ram
This behaviour is expected to be seen on all platforms
with this version (and probably many other versions).
---------------------
This is a verified bug in the sense that I have applied
a fix to the code, rebuilt it, and the new behaviour is
consistent with what the original code was attempting to
accomplish. The new behaviour is also more useful and,
unlike the old behaviour, consistent with what is stated
in the documentation regarding camera aspect ratio.
Also, there is code commented 'do this only once' in
render.c for FISHEYE which is executed many times because
of this problem. So I am confident in saying this is a bug.
---------------------
Description:
There is code in render.c to scale these cameras according
to the aspect ratio of the camera; for instance

camera {
 fisheye
 location <0,0,0>
 direction z
 right x*1.33 // scale for 4:3 image
 up y
}
If this is run with a 640x480 output image, it should make
a round image, touching the top and bottom, with black
space on left and right. In fact, it makes an elliptical image
which touches the frame edge on all 4 sides. When I say 'should'
I mean that this is how it is coded in render.c, as below, but
it does not work.

      x0 *= Camera_Aspect_Ratio;  /* intended to make image circular */


---------------------

I have figured out why, and I have a fix. When the above is
executed, except for the first ray traced, the 'Camera_Aspect_Ratio'
has been set to 1.0

Here are the salient parts of the fisheye code in create_ray():
----------
    case FISHEYE_CAMERA:
... lines deleted ...

      /* Get aspect ratio --> we want a circle (do this only once). */

      if (Precompute_Camera_Constants)
      {
        VLength(lx, FCR);
        VLength(ly, FCU);

        Camera_Aspect_Ratio = lx / ly;

        VNormalize(FCR, FCR);
        VNormalize(FCU, FCU);
        VNormalize(FCD, FCD);
      }

      /* Get polar coordinates. */

      x0 *= Camera_Aspect_Ratio;

      rad = sqrt(x0 * x0 + y0 * y0);

      /* If the pixel lies outside the unit circle no ray is traced. */

      if (rad > 1.0)
      {
        return(FALSE);
      }
... lines deleted ...

      initialize_ray_container_state(Ray, Precompute_Camera_Constants);

      Precompute_Camera_Constants = FALSE;
      break;


----------
The problem is visible in this code. The code within the
'if(Precompute_Camera_Constants)'
is only intended to be executed once; in fact, it is executed many times. On the first
call to create_ray(), the Precompute_Camera_Constants value is NOT cleared because
the 'if (rad > 1.0)' is true and the 'return FALSE' is taken. So, the code in
the first 'if' is executed again on the next call to create_ray(); since the FCR and
FCU
vectors have been normalized by then, the Camera_Aspect_Ratio will be set to 1.0,
causing
the scaling to fail. Precompute_Camera_Constants is not cleared until the first actual
ray trace occurs.

To fix this, it is not sufficient to clear Precompute_Camera_Constants in the first
'if';
if this is done, the first call to initialize_ray_container_state() will take place
with
FALSE in the second parameter, causing misbehaviour (camera's containing list is not
initialized) and crash.

Instead, TWO flags are needed; both are set TRUE in the same place as
Precompute_Camera_Constants
is; one controls the initialization of the camera scale, and is tested AND cleared in
the
first 'if'; the second is passed to initialize_ray_container_state() and cleared after
the call. I have tested this change and it works. I kept Precompute_Camera_Constants
for the
ray_container_state() call, and added a new static Precompute_Camera_AR. This declared
in the same place as Precompute_Camera_Constants and set TRUE in the same place. It
appears in the FISHEYE and OMNIMAX camera code as below:


      if (Precompute_Camera_AR)
      {
        VLength(lx, FCR);
        VLength(ly, FCU);

        Camera_Aspect_Ratio = lx / ly;

        VNormalize(FCR, FCR);
        VNormalize(FCU, FCU);
        VNormalize(FCD, FCD);
 Precompute_Camera_AR = FALSE; /* only once */
      }

------------------------------------------------
That was the bug and the fix. Here is a simple improvement to the OMNIMAX camera,
It can be applied at the same time without backwards compatibility problems,
since it has no effect for aspect_ratio = 1.0; and square images are the only
reasonable possibility with the current OMNIMAX because of the bug described above.
The purpose of the change is to improve the fitting of the OMNIMAX
image into the frame. The current scaling code is correct for a circular image, but
the OMNIMAX image is not circular. As a result of this problem, if you put an
OMNIMAX image into a 4:3 frame (after implementing the above fix), much space will be
lost on the bottom and both sides.
 The change is as follows, and is applied below "case OMNIMAX_CAMERA" in create_ray():

(I have shown 'before' and 'after' in #ifdef's)
----------

      /* Get polar coordinates. */

#if !defined(OMNIMAX_BETTER FIT)
      x0 *= Camera_Aspect_Ratio; /* current scaling method */
#endif
#if defined(OMNIMAX_BETTER FIT)  /* new method */
   /* improve screen usage. The image extends with x0 from -1 to +1
      but y0 only from -0.558329 to +1. The aspect ratio is thus 1.283.
   */
   if( Camera_Aspect_Ratio > 1.0 ){
    double scaleit;
    if( Camera_Aspect_Ratio < 1.283458){
     scaleit = Camera_Aspect_Ratio;
    }else{
     scaleit = 1.283458;
     x0 *= Camera_Aspect_Ratio/scaleit;
    }
    /* now, enlarge y-dimension by 'scaleit' (with y0=1 as origin),
       we have shrunk x-dimension so that the total warp = C.A.R.
   */
    y0 = (y0-1.0)/scaleit + 1.0;
   }else{
    y0 /= Camera_Aspect_Ratio; /* shrink for tall image */
   }
#endif

----------

In addition, the current scaling method doesn't work for tall images; if the
aspect ratio is less than 1, the image's sides will be cropped off for FISHEYE
and OMNIMAX. This misbehaviour has been masked in the past, since the Camera
Aspect Ratio has been ignored. The code above deals with this for the OMNIMAX
by 'y0 /= Camera_Aspect_Ratio' when Camera_Aspect_Ratio < 0. The fisheye camera
needs a similar fix.

--- Gregory Smith gre### [at] hotmailcom


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.