//============================================================================ // 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. //============================================================================ #ifndef vtk_m_rendering_raytracing_Ray_Operations_h #define vtk_m_rendering_raytracing_Ray_Operations_h #include #include #include #include #include #include #include namespace vtkm { namespace rendering { namespace raytracing { namespace detail { class RayStatusFilter : public vtkm::worklet::WorkletMapField { public: using ControlSignature = void(FieldIn, FieldInOut); using ExecutionSignature = void(_1, _2); VTKM_EXEC void operator()(const vtkm::Id& hitIndex, vtkm::UInt8& rayStatus) const { if (hitIndex == -1) rayStatus = RAY_EXITED_DOMAIN; else if (rayStatus != RAY_EXITED_DOMAIN && rayStatus != RAY_TERMINATED) rayStatus = RAY_ACTIVE; //else printf("Bad status state %d \n",(int)rayStatus); } }; //class RayStatusFileter class RayMapCanvas : public vtkm::worklet::WorkletMapField { protected: vtkm::Matrix InverseProjView; vtkm::Id Width; vtkm::Float32 DoubleInvHeight; vtkm::Float32 DoubleInvWidth; vtkm::Vec3f_32 Origin; public: VTKM_CONT RayMapCanvas(const vtkm::Matrix& inverseProjView, const vtkm::Id width, const vtkm::Id height, const vtkm::Vec3f_32& origin) : InverseProjView(inverseProjView) , Width(width) , Origin(origin) { VTKM_ASSERT(width > 0); VTKM_ASSERT(height > 0); DoubleInvHeight = 2.f / static_cast(height); DoubleInvWidth = 2.f / static_cast(width); } using ControlSignature = void(FieldIn, FieldInOut, FieldIn, WholeArrayIn); using ExecutionSignature = void(_1, _2, _3, _4); template VTKM_EXEC void operator()(const vtkm::Id& pixelId, Precision& maxDistance, const Vec& origin, const DepthPortalType& depths) const { vtkm::Vec4f_32 position; position[0] = static_cast(pixelId % Width); position[1] = static_cast(pixelId / Width); position[2] = static_cast(depths.Get(pixelId)); position[3] = 1; // transform into normalized device coordinates (-1,1) position[0] = position[0] * DoubleInvWidth - 1.f; position[1] = position[1] * DoubleInvHeight - 1.f; position[2] = 2.f * position[2] - 1.f; // offset so we don't go all the way to the same point position[2] -= 0.00001f; position = vtkm::MatrixMultiply(InverseProjView, position); vtkm::Vec3f_32 p; p[0] = position[0] / position[3]; p[1] = position[1] / position[3]; p[2] = position[2] / position[3]; p = p - origin; maxDistance = vtkm::Magnitude(p); } }; //class RayMapMinDistances } // namespace detail class RayOperations { public: template static void ResetStatus(Ray& rays, vtkm::UInt8 status) { vtkm::cont::ArrayHandleConstant statusHandle(status, rays.NumRays); vtkm::cont::Algorithm::Copy(statusHandle, rays.Status); } // // Some worklets like triangle intersection do not set the // ray status, so this operation sets the status based on // the ray hit index // template static void UpdateRayStatus(Ray& rays, Device) { vtkm::worklet::DispatcherMapField dispatcher{ ( detail::RayStatusFilter{}) }; dispatcher.SetDevice(Device()); dispatcher.Invoke(rays.HitIdx, rays.Status); } template static void UpdateRayStatus(Ray& rays) { vtkm::worklet::DispatcherMapField dispatcher{ ( detail::RayStatusFilter{}) }; dispatcher.Invoke(rays.HitIdx, rays.Status); } VTKM_RENDERING_EXPORT static void MapCanvasToRays(Ray& rays, const vtkm::rendering::Camera& camera, const vtkm::rendering::CanvasRayTracer& canvas); template static vtkm::Id RaysInMesh(Ray& rays) { vtkm::Vec maskValues; maskValues[0] = RAY_ACTIVE; maskValues[1] = RAY_LOST; vtkm::cont::ArrayHandle masks; vtkm::worklet::DispatcherMapField> dispatcher{ ( ManyMask{ maskValues }) }; dispatcher.Invoke(rays.Status, masks); vtkm::cont::ArrayHandleCast> castedMasks(masks); const vtkm::Id initVal = 0; vtkm::Id count = vtkm::cont::Algorithm::Reduce(castedMasks, initVal); return count; } template static vtkm::Id GetStatusCount(Ray& rays, vtkm::Id status) { vtkm::UInt8 statusUInt8; if (status < 0 || status > 255) { throw vtkm::cont::ErrorBadValue("Rays GetStatusCound: invalid status"); } statusUInt8 = static_cast(status); vtkm::cont::ArrayHandle masks; vtkm::worklet::DispatcherMapField> dispatcher{ ( Mask{ statusUInt8 }) }; dispatcher.Invoke(rays.Status, masks); vtkm::cont::ArrayHandleCast> castedMasks(masks); const vtkm::Id initVal = 0; vtkm::Id count = vtkm::cont::Algorithm::Reduce(castedMasks, initVal); return count; } template static vtkm::Id RaysProcessed(Ray& rays) { vtkm::Vec maskValues; maskValues[0] = RAY_TERMINATED; maskValues[1] = RAY_EXITED_DOMAIN; maskValues[2] = RAY_ABANDONED; vtkm::cont::ArrayHandle masks; vtkm::worklet::DispatcherMapField> dispatcher{ ( ManyMask{ maskValues }) }; dispatcher.Invoke(rays.Status, masks); vtkm::cont::ArrayHandleCast> castedMasks(masks); const vtkm::Id initVal = 0; vtkm::Id count = vtkm::cont::Algorithm::Reduce(castedMasks, initVal); return count; } template static vtkm::cont::ArrayHandle CompactActiveRays(Ray& rays) { vtkm::Vec maskValues; maskValues[0] = RAY_ACTIVE; auto statusUInt8 = static_cast(RAY_ACTIVE); vtkm::cont::ArrayHandle masks; vtkm::worklet::DispatcherMapField> dispatcher{ ( Mask{ statusUInt8 }) }; dispatcher.Invoke(rays.Status, masks); vtkm::cont::ArrayHandle emptyHandle; rays.Normal = vtkm::cont::make_ArrayHandleCompositeVector(emptyHandle, emptyHandle, emptyHandle); rays.Origin = vtkm::cont::make_ArrayHandleCompositeVector(emptyHandle, emptyHandle, emptyHandle); rays.Dir = vtkm::cont::make_ArrayHandleCompositeVector(emptyHandle, emptyHandle, emptyHandle); const vtkm::Int32 numFloatArrays = 18; vtkm::cont::ArrayHandle* floatArrayPointers[numFloatArrays]; floatArrayPointers[0] = &rays.OriginX; floatArrayPointers[1] = &rays.OriginY; floatArrayPointers[2] = &rays.OriginZ; floatArrayPointers[3] = &rays.DirX; floatArrayPointers[4] = &rays.DirY; floatArrayPointers[5] = &rays.DirZ; floatArrayPointers[6] = &rays.Distance; floatArrayPointers[7] = &rays.MinDistance; floatArrayPointers[8] = &rays.MaxDistance; floatArrayPointers[9] = &rays.Scalar; floatArrayPointers[10] = &rays.IntersectionX; floatArrayPointers[11] = &rays.IntersectionY; floatArrayPointers[12] = &rays.IntersectionZ; floatArrayPointers[13] = &rays.U; floatArrayPointers[14] = &rays.V; floatArrayPointers[15] = &rays.NormalX; floatArrayPointers[16] = &rays.NormalY; floatArrayPointers[17] = &rays.NormalZ; const int breakPoint = rays.IntersectionDataEnabled ? -1 : 9; for (int i = 0; i < numFloatArrays; ++i) { if (i == breakPoint) { break; } vtkm::cont::ArrayHandle compacted; vtkm::cont::Algorithm::CopyIf(*floatArrayPointers[i], masks, compacted); *floatArrayPointers[i] = compacted; } // // restore the composite vectors // rays.Normal = vtkm::cont::make_ArrayHandleCompositeVector(rays.NormalX, rays.NormalY, rays.NormalZ); rays.Origin = vtkm::cont::make_ArrayHandleCompositeVector(rays.OriginX, rays.OriginY, rays.OriginZ); rays.Dir = vtkm::cont::make_ArrayHandleCompositeVector(rays.DirX, rays.DirY, rays.DirZ); vtkm::cont::ArrayHandle compactedHits; vtkm::cont::Algorithm::CopyIf(rays.HitIdx, masks, compactedHits); rays.HitIdx = compactedHits; vtkm::cont::ArrayHandle compactedPixels; vtkm::cont::Algorithm::CopyIf(rays.PixelIdx, masks, compactedPixels); rays.PixelIdx = compactedPixels; vtkm::cont::ArrayHandle compactedStatus; vtkm::cont::Algorithm::CopyIf(rays.Status, masks, compactedStatus); rays.Status = compactedStatus; rays.NumRays = rays.Status.ReadPortal().GetNumberOfValues(); const auto bufferCount = static_cast(rays.Buffers.size()); for (size_t i = 0; i < bufferCount; ++i) { ChannelBufferOperations::Compact(rays.Buffers[i], masks, rays.NumRays); } return masks; } template static void Resize(Ray& rays, const vtkm::Int32 newSize) { if (newSize == rays.NumRays) return; //nothing to do rays.NumRays = newSize; if (rays.IntersectionDataEnabled) { rays.IntersectionX.Allocate(rays.NumRays); rays.IntersectionY.Allocate(rays.NumRays); rays.IntersectionZ.Allocate(rays.NumRays); rays.U.Allocate(rays.NumRays); rays.V.Allocate(rays.NumRays); rays.Scalar.Allocate(rays.NumRays); rays.NormalX.Allocate(rays.NumRays); rays.NormalY.Allocate(rays.NumRays); rays.NormalZ.Allocate(rays.NumRays); } rays.OriginX.Allocate(rays.NumRays); rays.OriginY.Allocate(rays.NumRays); rays.OriginZ.Allocate(rays.NumRays); rays.DirX.Allocate(rays.NumRays); rays.DirY.Allocate(rays.NumRays); rays.DirZ.Allocate(rays.NumRays); rays.Distance.Allocate(rays.NumRays); rays.MinDistance.Allocate(rays.NumRays); rays.MaxDistance.Allocate(rays.NumRays); rays.Status.Allocate(rays.NumRays); rays.HitIdx.Allocate(rays.NumRays); rays.PixelIdx.Allocate(rays.NumRays); for (auto&& buffer : rays.Buffers) { buffer.Resize(rays.NumRays); } } template static void CopyDistancesToMin(Ray rays, const T offset = 0.f) { vtkm::worklet::DispatcherMapField> dispatcher{ ( CopyAndOffsetMask{ offset, RAY_EXITED_MESH }) }; dispatcher.Invoke(rays.Distance, rays.MinDistance, rays.Status); } }; } } } // namespace vktm::rendering::raytracing #endif