1 //============================================================================ 2 // Copyright (c) Kitware, Inc. 3 // All rights reserved. 4 // See LICENSE.txt for details. 5 // 6 // This software is distributed WITHOUT ANY WARRANTY; without even 7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 8 // PURPOSE. See the above copyright notice for more information. 9 //============================================================================ 10 #ifndef vtk_m_rendering_raytracing_Ray_Operations_h 11 #define vtk_m_rendering_raytracing_Ray_Operations_h 12 13 #include <vtkm/Matrix.h> 14 #include <vtkm/rendering/Camera.h> 15 #include <vtkm/rendering/CanvasRayTracer.h> 16 #include <vtkm/rendering/raytracing/ChannelBufferOperations.h> 17 #include <vtkm/rendering/raytracing/Ray.h> 18 #include <vtkm/rendering/raytracing/Worklets.h> 19 #include <vtkm/rendering/vtkm_rendering_export.h> 20 21 namespace vtkm 22 { 23 namespace rendering 24 { 25 namespace raytracing 26 { 27 namespace detail 28 { 29 30 class RayStatusFilter : public vtkm::worklet::WorkletMapField 31 { 32 public: 33 VTKM_CONT RayStatusFilter()34 RayStatusFilter() {} 35 using ControlSignature = void(FieldIn, FieldInOut); 36 using ExecutionSignature = void(_1, _2); 37 VTKM_EXEC operator()38 void operator()(const vtkm::Id& hitIndex, vtkm::UInt8& rayStatus) const 39 { 40 if (hitIndex == -1) 41 rayStatus = RAY_EXITED_DOMAIN; 42 else if (rayStatus != RAY_EXITED_DOMAIN && rayStatus != RAY_TERMINATED) 43 rayStatus = RAY_ACTIVE; 44 //else printf("Bad status state %d \n",(int)rayStatus); 45 } 46 }; //class RayStatusFileter 47 48 class RayMapCanvas : public vtkm::worklet::WorkletMapField 49 { 50 protected: 51 vtkm::Matrix<vtkm::Float32, 4, 4> InverseProjView; 52 vtkm::Id Width; 53 vtkm::Float32 DoubleInvHeight; 54 vtkm::Float32 DoubleInvWidth; 55 vtkm::Vec3f_32 Origin; 56 57 public: 58 VTKM_CONT RayMapCanvas(const vtkm::Matrix<vtkm::Float32,4,4> & inverseProjView,const vtkm::Id width,const vtkm::Id height,const vtkm::Vec3f_32 & origin)59 RayMapCanvas(const vtkm::Matrix<vtkm::Float32, 4, 4>& inverseProjView, 60 const vtkm::Id width, 61 const vtkm::Id height, 62 const vtkm::Vec3f_32& origin) 63 : InverseProjView(inverseProjView) 64 , Width(width) 65 , Origin(origin) 66 { 67 VTKM_ASSERT(width > 0); 68 VTKM_ASSERT(height > 0); 69 DoubleInvHeight = 2.f / static_cast<vtkm::Float32>(height); 70 DoubleInvWidth = 2.f / static_cast<vtkm::Float32>(width); 71 } 72 73 using ControlSignature = void(FieldIn, FieldInOut, FieldIn, WholeArrayIn); 74 using ExecutionSignature = void(_1, _2, _3, _4); 75 76 template <typename Precision, typename DepthPortalType> operator()77 VTKM_EXEC void operator()(const vtkm::Id& pixelId, 78 Precision& maxDistance, 79 const Vec<Precision, 3>& origin, 80 const DepthPortalType& depths) const 81 { 82 vtkm::Vec4f_32 position; 83 position[0] = static_cast<vtkm::Float32>(pixelId % Width); 84 position[1] = static_cast<vtkm::Float32>(pixelId / Width); 85 position[2] = static_cast<vtkm::Float32>(depths.Get(pixelId)); 86 position[3] = 1; 87 // transform into normalized device coordinates (-1,1) 88 position[0] = position[0] * DoubleInvWidth - 1.f; 89 position[1] = position[1] * DoubleInvHeight - 1.f; 90 position[2] = 2.f * position[2] - 1.f; 91 // offset so we don't go all the way to the same point 92 position[2] -= 0.00001f; 93 position = vtkm::MatrixMultiply(InverseProjView, position); 94 vtkm::Vec3f_32 p; 95 p[0] = position[0] / position[3]; 96 p[1] = position[1] / position[3]; 97 p[2] = position[2] / position[3]; 98 p = p - origin; 99 100 101 maxDistance = vtkm::Magnitude(p); 102 } 103 }; //class RayMapMinDistances 104 105 } // namespace detail 106 class RayOperations 107 { 108 public: 109 template <typename T> ResetStatus(Ray<T> & rays,vtkm::UInt8 status)110 static void ResetStatus(Ray<T>& rays, vtkm::UInt8 status) 111 { 112 vtkm::cont::ArrayHandleConstant<vtkm::UInt8> statusHandle(status, rays.NumRays); 113 vtkm::cont::Algorithm::Copy(statusHandle, rays.Status); 114 } 115 116 // 117 // Some worklets like triangle intersection do not set the 118 // ray status, so this operation sets the status based on 119 // the ray hit index 120 // 121 template <typename Device, typename T> UpdateRayStatus(Ray<T> & rays,Device)122 static void UpdateRayStatus(Ray<T>& rays, Device) 123 { 124 vtkm::worklet::DispatcherMapField<detail::RayStatusFilter> dispatcher{ ( 125 detail::RayStatusFilter{}) }; 126 dispatcher.SetDevice(Device()); 127 dispatcher.Invoke(rays.HitIdx, rays.Status); 128 } 129 130 template <typename T> UpdateRayStatus(Ray<T> & rays)131 static void UpdateRayStatus(Ray<T>& rays) 132 { 133 vtkm::worklet::DispatcherMapField<detail::RayStatusFilter> dispatcher{ ( 134 detail::RayStatusFilter{}) }; 135 dispatcher.Invoke(rays.HitIdx, rays.Status); 136 } 137 138 VTKM_RENDERING_EXPORT static void MapCanvasToRays(Ray<vtkm::Float32>& rays, 139 const vtkm::rendering::Camera& camera, 140 const vtkm::rendering::CanvasRayTracer& canvas); 141 142 template <typename T> RaysInMesh(Ray<T> & rays)143 static vtkm::Id RaysInMesh(Ray<T>& rays) 144 { 145 vtkm::Vec<UInt8, 2> maskValues; 146 maskValues[0] = RAY_ACTIVE; 147 maskValues[1] = RAY_LOST; 148 149 vtkm::cont::ArrayHandle<vtkm::UInt8> masks; 150 151 vtkm::worklet::DispatcherMapField<ManyMask<vtkm::UInt8, 2>> dispatcher{ ( 152 ManyMask<vtkm::UInt8, 2>{ maskValues }) }; 153 dispatcher.Invoke(rays.Status, masks); 154 vtkm::cont::ArrayHandleCast<vtkm::Id, vtkm::cont::ArrayHandle<vtkm::UInt8>> castedMasks(masks); 155 const vtkm::Id initVal = 0; 156 vtkm::Id count = vtkm::cont::Algorithm::Reduce(castedMasks, initVal); 157 158 return count; 159 } 160 161 template <typename T> GetStatusCount(Ray<T> & rays,vtkm::Id status)162 static vtkm::Id GetStatusCount(Ray<T>& rays, vtkm::Id status) 163 { 164 vtkm::UInt8 statusUInt8; 165 if (status < 0 || status > 255) 166 { 167 throw vtkm::cont::ErrorBadValue("Rays GetStatusCound: invalid status"); 168 } 169 170 statusUInt8 = static_cast<vtkm::UInt8>(status); 171 vtkm::cont::ArrayHandle<vtkm::UInt8> masks; 172 173 vtkm::worklet::DispatcherMapField<Mask<vtkm::UInt8>> dispatcher{ ( 174 Mask<vtkm::UInt8>{ statusUInt8 }) }; 175 dispatcher.Invoke(rays.Status, masks); 176 vtkm::cont::ArrayHandleCast<vtkm::Id, vtkm::cont::ArrayHandle<vtkm::UInt8>> castedMasks(masks); 177 const vtkm::Id initVal = 0; 178 vtkm::Id count = vtkm::cont::Algorithm::Reduce(castedMasks, initVal); 179 180 return count; 181 } 182 183 template <typename T> RaysProcessed(Ray<T> & rays)184 static vtkm::Id RaysProcessed(Ray<T>& rays) 185 { 186 vtkm::Vec<UInt8, 3> maskValues; 187 maskValues[0] = RAY_TERMINATED; 188 maskValues[1] = RAY_EXITED_DOMAIN; 189 maskValues[2] = RAY_ABANDONED; 190 191 vtkm::cont::ArrayHandle<vtkm::UInt8> masks; 192 193 vtkm::worklet::DispatcherMapField<ManyMask<vtkm::UInt8, 3>> dispatcher{ ( 194 ManyMask<vtkm::UInt8, 3>{ maskValues }) }; 195 dispatcher.Invoke(rays.Status, masks); 196 vtkm::cont::ArrayHandleCast<vtkm::Id, vtkm::cont::ArrayHandle<vtkm::UInt8>> castedMasks(masks); 197 const vtkm::Id initVal = 0; 198 vtkm::Id count = vtkm::cont::Algorithm::Reduce(castedMasks, initVal); 199 200 return count; 201 } 202 203 template <typename T> CompactActiveRays(Ray<T> & rays)204 static vtkm::cont::ArrayHandle<vtkm::UInt8> CompactActiveRays(Ray<T>& rays) 205 { 206 vtkm::Vec<UInt8, 1> maskValues; 207 maskValues[0] = RAY_ACTIVE; 208 vtkm::UInt8 statusUInt8 = static_cast<vtkm::UInt8>(RAY_ACTIVE); 209 vtkm::cont::ArrayHandle<vtkm::UInt8> masks; 210 211 vtkm::worklet::DispatcherMapField<Mask<vtkm::UInt8>> dispatcher{ ( 212 Mask<vtkm::UInt8>{ statusUInt8 }) }; 213 dispatcher.Invoke(rays.Status, masks); 214 215 vtkm::cont::ArrayHandle<T> emptyHandle; 216 217 rays.Normal = 218 vtkm::cont::make_ArrayHandleCompositeVector(emptyHandle, emptyHandle, emptyHandle); 219 rays.Origin = 220 vtkm::cont::make_ArrayHandleCompositeVector(emptyHandle, emptyHandle, emptyHandle); 221 rays.Dir = vtkm::cont::make_ArrayHandleCompositeVector(emptyHandle, emptyHandle, emptyHandle); 222 223 const vtkm::Int32 numFloatArrays = 18; 224 vtkm::cont::ArrayHandle<T>* floatArrayPointers[numFloatArrays]; 225 floatArrayPointers[0] = &rays.OriginX; 226 floatArrayPointers[1] = &rays.OriginY; 227 floatArrayPointers[2] = &rays.OriginZ; 228 floatArrayPointers[3] = &rays.DirX; 229 floatArrayPointers[4] = &rays.DirY; 230 floatArrayPointers[5] = &rays.DirZ; 231 floatArrayPointers[6] = &rays.Distance; 232 floatArrayPointers[7] = &rays.MinDistance; 233 floatArrayPointers[8] = &rays.MaxDistance; 234 235 floatArrayPointers[9] = &rays.Scalar; 236 floatArrayPointers[10] = &rays.IntersectionX; 237 floatArrayPointers[11] = &rays.IntersectionY; 238 floatArrayPointers[12] = &rays.IntersectionZ; 239 floatArrayPointers[13] = &rays.U; 240 floatArrayPointers[14] = &rays.V; 241 floatArrayPointers[15] = &rays.NormalX; 242 floatArrayPointers[16] = &rays.NormalY; 243 floatArrayPointers[17] = &rays.NormalZ; 244 245 const int breakPoint = rays.IntersectionDataEnabled ? -1 : 9; 246 for (int i = 0; i < numFloatArrays; ++i) 247 { 248 if (i == breakPoint) 249 { 250 break; 251 } 252 vtkm::cont::ArrayHandle<T> compacted; 253 vtkm::cont::Algorithm::CopyIf(*floatArrayPointers[i], masks, compacted); 254 *floatArrayPointers[i] = compacted; 255 } 256 257 // 258 // restore the composite vectors 259 // 260 rays.Normal = 261 vtkm::cont::make_ArrayHandleCompositeVector(rays.NormalX, rays.NormalY, rays.NormalZ); 262 rays.Origin = 263 vtkm::cont::make_ArrayHandleCompositeVector(rays.OriginX, rays.OriginY, rays.OriginZ); 264 rays.Dir = vtkm::cont::make_ArrayHandleCompositeVector(rays.DirX, rays.DirY, rays.DirZ); 265 266 vtkm::cont::ArrayHandle<vtkm::Id> compactedHits; 267 vtkm::cont::Algorithm::CopyIf(rays.HitIdx, masks, compactedHits); 268 rays.HitIdx = compactedHits; 269 270 vtkm::cont::ArrayHandle<vtkm::Id> compactedPixels; 271 vtkm::cont::Algorithm::CopyIf(rays.PixelIdx, masks, compactedPixels); 272 rays.PixelIdx = compactedPixels; 273 274 vtkm::cont::ArrayHandle<vtkm::UInt8> compactedStatus; 275 vtkm::cont::Algorithm::CopyIf(rays.Status, masks, compactedStatus); 276 rays.Status = compactedStatus; 277 278 rays.NumRays = rays.Status.ReadPortal().GetNumberOfValues(); 279 280 const size_t bufferCount = static_cast<size_t>(rays.Buffers.size()); 281 for (size_t i = 0; i < bufferCount; ++i) 282 { 283 ChannelBufferOperations::Compact(rays.Buffers[i], masks, rays.NumRays); 284 } 285 return masks; 286 } 287 288 template <typename Device, typename T> Resize(Ray<T> & rays,const vtkm::Int32 newSize,Device)289 static void Resize(Ray<T>& rays, const vtkm::Int32 newSize, Device) 290 { 291 if (newSize == rays.NumRays) 292 return; //nothing to do 293 294 rays.NumRays = newSize; 295 vtkm::cont::Token token; 296 297 if (rays.IntersectionDataEnabled) 298 { 299 rays.IntersectionX.PrepareForOutput(rays.NumRays, Device(), token); 300 rays.IntersectionY.PrepareForOutput(rays.NumRays, Device(), token); 301 rays.IntersectionZ.PrepareForOutput(rays.NumRays, Device(), token); 302 rays.U.PrepareForOutput(rays.NumRays, Device(), token); 303 rays.V.PrepareForOutput(rays.NumRays, Device(), token); 304 rays.Scalar.PrepareForOutput(rays.NumRays, Device(), token); 305 306 rays.NormalX.PrepareForOutput(rays.NumRays, Device(), token); 307 rays.NormalY.PrepareForOutput(rays.NumRays, Device(), token); 308 rays.NormalZ.PrepareForOutput(rays.NumRays, Device(), token); 309 } 310 311 rays.OriginX.PrepareForOutput(rays.NumRays, Device(), token); 312 rays.OriginY.PrepareForOutput(rays.NumRays, Device(), token); 313 rays.OriginZ.PrepareForOutput(rays.NumRays, Device(), token); 314 315 rays.DirX.PrepareForOutput(rays.NumRays, Device(), token); 316 rays.DirY.PrepareForOutput(rays.NumRays, Device(), token); 317 rays.DirZ.PrepareForOutput(rays.NumRays, Device(), token); 318 319 rays.Distance.PrepareForOutput(rays.NumRays, Device(), token); 320 rays.MinDistance.PrepareForOutput(rays.NumRays, Device(), token); 321 rays.MaxDistance.PrepareForOutput(rays.NumRays, Device(), token); 322 rays.Status.PrepareForOutput(rays.NumRays, Device(), token); 323 rays.HitIdx.PrepareForOutput(rays.NumRays, Device(), token); 324 rays.PixelIdx.PrepareForOutput(rays.NumRays, Device(), token); 325 326 const size_t bufferCount = static_cast<size_t>(rays.Buffers.size()); 327 for (size_t i = 0; i < bufferCount; ++i) 328 { 329 rays.Buffers[i].Resize(rays.NumRays, Device()); 330 } 331 } 332 333 template <typename T> 334 static void CopyDistancesToMin(Ray<T> rays, const T offset = 0.f) 335 { 336 vtkm::worklet::DispatcherMapField<CopyAndOffsetMask<T>> dispatcher{ ( 337 CopyAndOffsetMask<T>{ offset, RAY_EXITED_MESH }) }; 338 dispatcher.Invoke(rays.Distance, rays.MinDistance, rays.Status); 339 } 340 }; 341 } 342 } 343 } // namespace vktm::rendering::raytracing 344 #endif 345