diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2016-10-22 16:59:23 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2016-10-22 17:37:26 +0300 |
commit | 9d0ac94d52268ff34ce645035d4315d6018d02b9 (patch) | |
tree | 407595f970a244fd186cc2de176f8897bf315da3 /intern/cycles/kernel/kernel_camera.h | |
parent | b5d527ff6c7e01b73c14d8e01b7e33a697d30b12 (diff) |
Fix T49750: Cycles wrong ray differentials for perspective and stereo cameras.
Diffstat (limited to 'intern/cycles/kernel/kernel_camera.h')
-rw-r--r-- | intern/cycles/kernel/kernel_camera.h | 145 |
1 files changed, 94 insertions, 51 deletions
diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h index ed9726e1b51..de3d70bc774 100644 --- a/intern/cycles/kernel/kernel_camera.h +++ b/intern/cycles/kernel/kernel_camera.h @@ -105,39 +105,61 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo } #endif - float3 tP = transform_point(&cameratoworld, ray->P); - float3 tD = transform_direction(&cameratoworld, ray->D); - ray->P = spherical_stereo_position(kg, tD, tP); - ray->D = spherical_stereo_direction(kg, tD, tP, ray->P); + ray->P = transform_point(&cameratoworld, ray->P); + ray->D = normalize(transform_direction(&cameratoworld, ray->D)); + bool use_stereo = kernel_data.cam.interocular_offset != 0.0f; + if (!use_stereo) { + /* No stereo */ #ifdef __RAY_DIFFERENTIALS__ - /* ray differential */ - ray->dP = differential3_zero(); - - float3 tD_diff = transform_direction(&cameratoworld, Pcamera); - float3 Pdiff = spherical_stereo_position(kg, tD_diff, Pcamera); - float3 Ddiff = spherical_stereo_direction(kg, tD_diff, Pcamera, Pdiff); - - tP = transform_perspective(&rastertocamera, - make_float3(raster_x + 1.0f, raster_y, 0.0f)); - tD = tD_diff + float4_to_float3(kernel_data.cam.dx); - Pcamera = spherical_stereo_position(kg, tD, tP); - ray->dD.dx = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff; - ray->dP.dx = Pcamera - Pdiff; - - tP = transform_perspective(&rastertocamera, - make_float3(raster_x, raster_y + 1.0f, 0.0f)); - tD = tD_diff + float4_to_float3(kernel_data.cam.dy); - Pcamera = spherical_stereo_position(kg, tD, tP); - ray->dD.dy = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff; - /* dP.dy is zero, since the omnidirectional panorama only shift the eyes horizontally */ + float3 Dcenter = transform_direction(&cameratoworld, Pcamera); + + ray->dP = differential3_zero(); + ray->dD.dx = normalize(Dcenter + float4_to_float3(kernel_data.cam.dx)) - normalize(Dcenter); + ray->dD.dy = normalize(Dcenter + float4_to_float3(kernel_data.cam.dy)) - normalize(Dcenter); +#endif + } + else { + /* Spherical stereo */ + spherical_stereo_transform(kg, &ray->P, &ray->D); + +#ifdef __RAY_DIFFERENTIALS__ + /* Ray differentials, computed from scratch using the raster coordinates + * because we don't want to be affected by depth of field. We compute + * ray origin and direction for the center and two neighbouring pixels + * and simply take their differences. */ + float3 Pnostereo = transform_point(&cameratoworld, make_float3(0.0f, 0.0f, 0.0f)); + + float3 Pcenter = Pnostereo; + float3 Dcenter = Pcamera; + Dcenter = normalize(transform_direction(&cameratoworld, Dcenter)); + spherical_stereo_transform(kg, &Pcenter, &Dcenter); + + float3 Px = Pnostereo; + float3 Dx = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f)); + Dx = normalize(transform_direction(&cameratoworld, Dx)); + spherical_stereo_transform(kg, &Px, &Dx); + + ray->dP.dx = Px - Pcenter; + ray->dD.dx = Dx - Dcenter; + + float3 Py = Pnostereo; + float3 Dy = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f)); + Dy = normalize(transform_direction(&cameratoworld, Dy)); + spherical_stereo_transform(kg, &Py, &Dy); + + ray->dP.dy = Py - Pcenter; + ray->dD.dy = Dy - Dcenter; #endif + } #ifdef __CAMERA_CLIPPING__ /* clipping */ - float3 Pclip = normalize(Pcamera); - float z_inv = 1.0f / Pclip.z; - ray->P += kernel_data.cam.nearclip*ray->D * z_inv; + float z_inv = 1.0f / normalize(Pcamera).z; + float nearclip = kernel_data.cam.nearclip * z_inv; + ray->P += nearclip * ray->D; + ray->dP.dx += nearclip * ray->dD.dx; + ray->dP.dy += nearclip * ray->dD.dy; ray->t = kernel_data.cam.cliplength * z_inv; #else ray->t = FLT_MAX; @@ -268,36 +290,57 @@ ccl_device_inline void camera_sample_panorama(KernelGlobals *kg, } #endif - float3 tP = transform_point(&cameratoworld, ray->P); - float3 tD = transform_direction(&cameratoworld, ray->D); - ray->P = spherical_stereo_position(kg, tD, tP); - ray->D = spherical_stereo_direction(kg, tD, tP, ray->P); + ray->P = transform_point(&cameratoworld, ray->P); + ray->D = normalize(transform_direction(&cameratoworld, ray->D)); + + /* Stereo transform */ + bool use_stereo = kernel_data.cam.interocular_offset != 0.0f; + if (use_stereo) { + spherical_stereo_transform(kg, &ray->P, &ray->D); + } #ifdef __RAY_DIFFERENTIALS__ - /* ray differential */ - ray->dP = differential3_zero(); - - tP = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); - tD = transform_direction(&cameratoworld, panorama_to_direction(kg, tP.x, tP.y)); - float3 Pdiff = spherical_stereo_position(kg, tD, tP); - float3 Ddiff = spherical_stereo_direction(kg, tD, tP, Pdiff); - - tP = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f)); - tD = transform_direction(&cameratoworld, panorama_to_direction(kg, tP.x, tP.y)); - Pcamera = spherical_stereo_position(kg, tD, tP); - ray->dD.dx = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff; - ray->dP.dx = Pcamera - Pdiff; - - tP = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f)); - tD = transform_direction(&cameratoworld, panorama_to_direction(kg, tP.x, tP.y)); - Pcamera = spherical_stereo_position(kg, tD, tP); - ray->dD.dy = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff; - /* dP.dy is zero, since the omnidirectional panorama only shift the eyes horizontally */ + /* Ray differentials, computed from scratch using the raster coordinates + * because we don't want to be affected by depth of field. We compute + * ray origin and direction for the center and two neighbouring pixels + * and simply take their differences. */ + float3 Pcenter = Pcamera; + float3 Dcenter = panorama_to_direction(kg, Pcenter.x, Pcenter.y); + Pcenter = transform_point(&cameratoworld, Pcenter); + Dcenter = normalize(transform_direction(&cameratoworld, Dcenter)); + if (use_stereo) { + spherical_stereo_transform(kg, &Pcenter, &Dcenter); + } + + float3 Px = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f)); + float3 Dx = panorama_to_direction(kg, Px.x, Px.y); + Px = transform_point(&cameratoworld, Px); + Dx = normalize(transform_direction(&cameratoworld, Dx)); + if (use_stereo) { + spherical_stereo_transform(kg, &Px, &Dx); + } + + ray->dP.dx = Px - Pcenter; + ray->dD.dx = Dx - Dcenter; + + float3 Py = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f)); + float3 Dy = panorama_to_direction(kg, Py.x, Py.y); + Py = transform_point(&cameratoworld, Py); + Dy = normalize(transform_direction(&cameratoworld, Dy)); + if (use_stereo) { + spherical_stereo_transform(kg, &Py, &Dy); + } + + ray->dP.dy = Py - Pcenter; + ray->dD.dy = Dy - Dcenter; #endif #ifdef __CAMERA_CLIPPING__ /* clipping */ - ray->P += kernel_data.cam.nearclip*ray->D; + float nearclip = kernel_data.cam.nearclip; + ray->P += nearclip * ray->D; + ray->dP.dx += nearclip * ray->dD.dx; + ray->dP.dy += nearclip * ray->dD.dy; ray->t = kernel_data.cam.cliplength; #else ray->t = FLT_MAX; |