|
OverviewFor this lab, I decided to attempt to create motion blur as in Exercise 6.1 of the text. The idea here is to implement motion blur by modifying the Camera class in pbrt to make use of the time value for each ray. Instead of applying one CameraToWorld Transformation, we would like to apply a CameraToWorld transformation that is dependent on the time t that the ray is cast. The crux of the problem is to implement the Camera with two transformations, one at the initial time, t0, and a second which contains the transformation at the final time, t1, and to then interpolate between them for all t in [t0, t1].For this purpose, I first chose to implement Alexa's 2002 paper which gives a unique method for interpolating matrices based on a different multiplication operator. Alexa's argument is that normal matrix multiplication is not commutative, i.e. for two matrices A,B, AB != BA, so instead he implements a new operator. This operator is based on being able to efficiently perform exp(A), log(A), and sqrt(A) efficiently for some matrix A. As a result, a new way to interpolate between two matrices is shown. My implementation required changing four pbrt files; in the core/ directory I fiddled with pbrt.h, util.cpp, transform.h and transform.cpp. I also implemented a new camera, blur.cpp which implements these changes. Mostly, my changes boiled down to modifying the Matrix4x4 class and the Transform class to implement the matrix operations described in this paper. After implementing, I noticed one major holdup---doing this sort of interpolation is slow for arbitrary t. To calculate a matrix M that is interpolated between A and B for some time t, the operation boils down to calculate M = exp((1-t)*log(A) + t*log(B)). Since I would have to apply this operation for each ray, I chose to do an approximation where I precalculate a vector of position matrices between A and B for timesteps t + n*0.01 with n in [0, 100] (assuming t ranges from 0 to 1, which it did in my experiments). Unfortunately, my initial attempt at implementing this failed. I realized after debugging that the problem is the sqrt(A) method I was using (based on the one in the Appendix of Alexa 2002) does not converge in all cases. In particular, the sqrt(A) for a matrix A has complex values if the matrix A is not positive definite and consequently the algorithm to compute sqrt(A) failed. Since computing the log(A) requires computing the sqrt(A), I was not able to apply Alexa's operator My fallback plan was to implement the interpolation using the interpolation with quaternions used by Shoemake. However, I realized based on my inputs that this was sort of a silly idea. What I initially do is pass in the two sets of input parameters for the LookAt() function, i.e. the eye, look, and up vectors for both the initial and final camera transformation. Then, in my camera class, I called LookAt() twice and used Alexa's technique to interpolate between them. Instead, it makes much more sense to just linearly interpolate between the two sets of points, i.e. eye0 to eye1, look0 to look1, etc, and then call LookAt with the appropriate inputs. This is essentially what the decomposition of the transformation would do to get the different translation, rotation, and scaling, but since I already had the information (albeit in a different form) I decided to use this hack to do the blurring. In my framework, this technique essentially boils down to calling LookAt initially with 100 steps between the two sets of input eye, look, and up vectors. In this manner, I initialize 100 transformation matrices and then in my GenerateRay() method I floor the rays time to an index into this array of matrices. The results we get here (shown below) work quite successfully. ResultsBelow I show some results for a sample scene and some destination transformations. I compare the results of my technique with that of just linearly interpolating the transformation matrices element-wise. First I show just a shift in one direction:
From the above, we can see that a typical shift (here we moved the eye vector from (1,1,8) to (5,1,8)) actually gives pretty similar results with both the linear technique and my technique. This is actually because of how the eye vector fits into the transformation used for the camera; and in fact linearly interpolating between the transformation works here. I should note here that while they are similar results, it appears to me that the shift looks slightly backwards in the linear case. I'm not sure if this is a sampling artifact or a result of the linear interpolation being the wrong way to do it. Next we examine a simple rotation of the same scene:
Here we can see where the linear interpolation component-wise breaks down while our technique does not. We've rotated the up vector from (0, 1, 0) to (1, 0, 0) in the above scenes. The linear technique attempts to jump across the rotation instead of going smoothly through, resulting in a blur that doesn't smoothly go through the full rotation between them. ConclusionsWe can draw a number of conclusions from the results above. First, I would like to point out I'm a bit disappointed with Alexa's 2002 paper. After reading it I was a bit excited at what it promised, but I naively did not examine the practical aspects of performing this new operation numerically on a computer. In addition to being expensive, it flat out will not work for some matrices on which the square root is not well defined.I do however think I've found a nice compromise using what I had and the time I had. It's clear from the above that linear interpolation element-wise of the transformation matrix is not successful, even from the simple examples above. However, linear interpolation of the three components that go into the transformation matrix calculation worked quite well. Had I more time, I would invest more experimental time in trying out different scenes and different transformations. Also, I think a neat experiment would be to interpolate between the transformation matrices in a nonlinear way, something that balances more weight on either the initial or final transformation to adjust how the blur looks. |