//============================================================================ // Copyright (c) Kitware, Inc. // All rights reserved. // See LICENSE.txt for details. // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notice for more information. //============================================================================ #include #include #include #include #include #include #include namespace vtkm { namespace rendering { namespace internal { class SurfaceConverter : public vtkm::worklet::WorkletMapField { vtkm::Matrix ViewProjMat; public: VTKM_CONT SurfaceConverter(const vtkm::Matrix viewProjMat) : ViewProjMat(viewProjMat) { } using ControlSignature = void(FieldIn, WholeArrayInOut, FieldIn, FieldIn, FieldIn, WholeArrayInOut, WholeArrayInOut); using ExecutionSignature = void(_1, _2, _3, _4, _5, _6, _7, WorkIndex); template VTKM_EXEC void operator()(const vtkm::Id& pixelIndex, ColorPortalType& colorBufferIn, const Precision& inDepth, const vtkm::Vec& origin, const vtkm::Vec& dir, DepthBufferPortalType& depthBuffer, ColorBufferPortalType& colorBuffer, const vtkm::Id& index) const { vtkm::Vec intersection = origin + inDepth * dir; vtkm::Vec4f_32 point; point[0] = static_cast(intersection[0]); point[1] = static_cast(intersection[1]); point[2] = static_cast(intersection[2]); point[3] = 1.f; vtkm::Float32 depth; { vtkm::Vec4f_32 newpoint; newpoint = vtkm::MatrixMultiply(this->ViewProjMat, point); if (newpoint[3] > 0) { depth = 0.5f * (newpoint[2] / newpoint[3]) + 0.5f; } else { // This condition can happen when the ray is at the origin (inDepth = 0), which is a // singularity in the projection matrix. I'm not sure this is the right think to do since // it looks like depth is supposed to be between 0 and 1. It seems wrong that you would // ever get a ray in front of the near plane, so the "right" solution may be to fix this // elsewhere. depth = vtkm::NegativeInfinity32(); } } vtkm::Vec4f_32 color; color[0] = static_cast(colorBufferIn.Get(index * 4 + 0)); color[1] = static_cast(colorBufferIn.Get(index * 4 + 1)); color[2] = static_cast(colorBufferIn.Get(index * 4 + 2)); color[3] = static_cast(colorBufferIn.Get(index * 4 + 3)); // blend the mapped color with existing canvas color vtkm::Vec4f_32 inColor = colorBuffer.Get(pixelIndex); // if transparency exists, all alphas have been pre-multiplied vtkm::Float32 alpha = (1.f - color[3]); color[0] = color[0] + inColor[0] * alpha; color[1] = color[1] + inColor[1] * alpha; color[2] = color[2] + inColor[2] * alpha; color[3] = inColor[3] * alpha + color[3]; // clamp for (vtkm::Int32 i = 0; i < 4; ++i) { color[i] = vtkm::Min(1.f, vtkm::Max(color[i], 0.f)); } // The existing depth should already been feed into the ray mapper // so no color contribution will exist past the existing depth. depthBuffer.Set(pixelIndex, depth); colorBuffer.Set(pixelIndex, color); } }; //class SurfaceConverter template VTKM_CONT void WriteToCanvas(const vtkm::rendering::raytracing::Ray& rays, const vtkm::cont::ArrayHandle& colors, const vtkm::rendering::Camera& camera, vtkm::rendering::CanvasRayTracer* canvas) { vtkm::Matrix viewProjMat = vtkm::MatrixMultiply(camera.CreateProjectionMatrix(canvas->GetWidth(), canvas->GetHeight()), camera.CreateViewMatrix()); vtkm::worklet::DispatcherMapField(SurfaceConverter(viewProjMat)) .Invoke(rays.PixelIdx, colors, rays.Distance, rays.Origin, rays.Dir, canvas->GetDepthBuffer(), canvas->GetColorBuffer()); //Force the transfer so the vectors contain data from device canvas->GetColorBuffer().WritePortal().Get(0); canvas->GetDepthBuffer().WritePortal().Get(0); } } // namespace internal CanvasRayTracer::CanvasRayTracer(vtkm::Id width, vtkm::Id height) : Canvas(width, height) { } CanvasRayTracer::~CanvasRayTracer() {} void CanvasRayTracer::WriteToCanvas(const vtkm::rendering::raytracing::Ray& rays, const vtkm::cont::ArrayHandle& colors, const vtkm::rendering::Camera& camera) { internal::WriteToCanvas(rays, colors, camera, this); } void CanvasRayTracer::WriteToCanvas(const vtkm::rendering::raytracing::Ray& rays, const vtkm::cont::ArrayHandle& colors, const vtkm::rendering::Camera& camera) { internal::WriteToCanvas(rays, colors, camera, this); } vtkm::rendering::Canvas* CanvasRayTracer::NewCopy() const { return new vtkm::rendering::CanvasRayTracer(*this); } } }