From 39b347dbd069dba2fa68eb5f6c1b1641001fa543 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Mon, 7 May 2018 18:03:03 -0600 Subject: [PATCH 1/2] Fix raytrace using wrong fov with standard camera The raytracing code has its own version of camera that maintains two field of view (fov) parameters: one for the x direction and one for the y. The standard vtkm::rendering::Camera contains only one fov. As is consistent with OpenGL's gluPerspective and VTK's camera, the fov is specified in the y direction. However, the raytracing code was incorrectly using it in the x direction. That caused it to do a weird rescaling when the aspect ratio was not 1. --- vtkm/rendering/raytracing/Camera.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vtkm/rendering/raytracing/Camera.cxx b/vtkm/rendering/raytracing/Camera.cxx index ca80cc6bb..9ee6645e1 100644 --- a/vtkm/rendering/raytracing/Camera.cxx +++ b/vtkm/rendering/raytracing/Camera.cxx @@ -455,7 +455,7 @@ void Camera::SetHeight(const vtkm::Int32& height) if (Height != height) { this->Height = height; - this->SetFieldOfView(this->FovX); + this->SetFieldOfView(this->FovY); } } @@ -475,7 +475,7 @@ void Camera::SetWidth(const vtkm::Int32& width) if (this->Width != width) { this->Width = width; - this->SetFieldOfView(this->FovX); + this->SetFieldOfView(this->FovY); } } @@ -529,8 +529,8 @@ void Camera::SetFieldOfView(const vtkm::Float32& degrees) throw vtkm::cont::ErrorBadValue("Camera feild of view must be less than 180."); } - vtkm::Float32 newFOVY = (vtkm::Float32(this->Height) / vtkm::Float32(this->Width)) * degrees; - vtkm::Float32 newFOVX = degrees; + vtkm::Float32 newFOVY = degrees; + vtkm::Float32 newFOVX = (vtkm::Float32(this->Width) / vtkm::Float32(this->Height)) * degrees; if (newFOVX != this->FovX) { this->IsViewDirty = true; @@ -541,13 +541,13 @@ void Camera::SetFieldOfView(const vtkm::Float32& degrees) } this->FovX = newFOVX; this->FovY = newFOVY; - this->CameraView.SetFieldOfView(this->FovX); + this->CameraView.SetFieldOfView(this->FovY); } VTKM_CONT vtkm::Float32 Camera::GetFieldOfView() const { - return this->FovX; + return this->FovY; } VTKM_CONT From 0da5573085539d17d5f5480249711c115c1cdd38 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Mon, 7 May 2018 18:40:45 -0600 Subject: [PATCH 2/2] Fix scaling of x/y field of views Prevously, the x field of view was computed by scaling the y field of view by the aspect ratio of the canvas. However, this is wrong because the field of view angles do not scale linearly with the aspect ratio. Fix this issue by using trig functions to convert the angle to distance, scale the distance, and then convert back to angle. --- vtkm/rendering/raytracing/Camera.cxx | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/vtkm/rendering/raytracing/Camera.cxx b/vtkm/rendering/raytracing/Camera.cxx index 9ee6645e1..e4d065d8c 100644 --- a/vtkm/rendering/raytracing/Camera.cxx +++ b/vtkm/rendering/raytracing/Camera.cxx @@ -530,7 +530,31 @@ void Camera::SetFieldOfView(const vtkm::Float32& degrees) } vtkm::Float32 newFOVY = degrees; - vtkm::Float32 newFOVX = (vtkm::Float32(this->Width) / vtkm::Float32(this->Height)) * degrees; + vtkm::Float32 newFOVX; + + if (this->Width != this->Height) + { + vtkm::Float32 fovyRad = (newFOVY * static_cast(vtkm::Pi())) / 180.0f; + + // Use the tan function to find the distance from the center of the image to the top (or + // bottom). (Actually, we are finding the ratio of this distance to the near plane distance, + // but since we scale everything by the near plane distance, we can use this ratio as a scaled + // proxy of the distances we need.) + vtkm::Float32 verticalDistance = vtkm::Tan(0.5f * fovyRad); + + // Scale the vertical distance by the aspect ratio to get the horizontal distance. + vtkm::Float32 aspectRatio = vtkm::Float32(this->Width) / vtkm::Float32(this->Height); + vtkm::Float32 horizontalDistance = aspectRatio * verticalDistance; + + // Now use the arctan function to get the proper field of view in the x direction. + vtkm::Float32 fovxRad = 2.0f * vtkm::ATan(horizontalDistance); + newFOVX = 180.0f * (fovxRad / static_cast(vtkm::Pi())); + } + else + { + newFOVX = newFOVY; + } + if (newFOVX != this->FovX) { this->IsViewDirty = true;