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 #include <vtkm/rendering/raytracing/RayTracer.h>
11 
12 #include <iostream>
13 #include <math.h>
14 #include <stdio.h>
15 #include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
16 #include <vtkm/cont/ColorTable.h>
17 #include <vtkm/cont/Timer.h>
18 
19 #include <vtkm/rendering/raytracing/Camera.h>
20 #include <vtkm/rendering/raytracing/Logger.h>
21 #include <vtkm/rendering/raytracing/RayTracingTypeDefs.h>
22 #include <vtkm/worklet/DispatcherMapField.h>
23 #include <vtkm/worklet/WorkletMapField.h>
24 
25 namespace vtkm
26 {
27 namespace rendering
28 {
29 namespace raytracing
30 {
31 
32 namespace detail
33 {
34 
35 class SurfaceColor
36 {
37 public:
38   class Shade : public vtkm::worklet::WorkletMapField
39   {
40   private:
41     vtkm::Vec3f_32 LightPosition;
42     vtkm::Vec3f_32 LightAbmient;
43     vtkm::Vec3f_32 LightDiffuse;
44     vtkm::Vec3f_32 LightSpecular;
45     vtkm::Float32 SpecularExponent;
46     vtkm::Vec3f_32 CameraPosition;
47     vtkm::Vec3f_32 LookAt;
48 
49   public:
50     VTKM_CONT
Shade(const vtkm::Vec3f_32 & lightPosition,const vtkm::Vec3f_32 & cameraPosition,const vtkm::Vec3f_32 & lookAt)51     Shade(const vtkm::Vec3f_32& lightPosition,
52           const vtkm::Vec3f_32& cameraPosition,
53           const vtkm::Vec3f_32& lookAt)
54       : LightPosition(lightPosition)
55       , CameraPosition(cameraPosition)
56       , LookAt(lookAt)
57     {
58       //Set up some default lighting parameters for now
59       LightAbmient[0] = .5f;
60       LightAbmient[1] = .5f;
61       LightAbmient[2] = .5f;
62       LightDiffuse[0] = .7f;
63       LightDiffuse[1] = .7f;
64       LightDiffuse[2] = .7f;
65       LightSpecular[0] = .7f;
66       LightSpecular[1] = .7f;
67       LightSpecular[2] = .7f;
68       SpecularExponent = 20.f;
69     }
70 
71     using ControlSignature =
72       void(FieldIn, FieldIn, FieldIn, FieldIn, WholeArrayInOut, WholeArrayIn);
73     using ExecutionSignature = void(_1, _2, _3, _4, _5, _6, WorkIndex);
74 
75     template <typename ColorPortalType, typename Precision, typename ColorMapPortalType>
operator ()(const vtkm::Id & hitIdx,const Precision & scalar,const vtkm::Vec<Precision,3> & normal,const vtkm::Vec<Precision,3> & intersection,ColorPortalType & colors,ColorMapPortalType colorMap,const vtkm::Id & idx) const76     VTKM_EXEC void operator()(const vtkm::Id& hitIdx,
77                               const Precision& scalar,
78                               const vtkm::Vec<Precision, 3>& normal,
79                               const vtkm::Vec<Precision, 3>& intersection,
80                               ColorPortalType& colors,
81                               ColorMapPortalType colorMap,
82                               const vtkm::Id& idx) const
83     {
84       vtkm::Vec<Precision, 4> color;
85       vtkm::Id offset = idx * 4;
86 
87       if (hitIdx < 0)
88       {
89         return;
90       }
91 
92       color[0] = colors.Get(offset + 0);
93       color[1] = colors.Get(offset + 1);
94       color[2] = colors.Get(offset + 2);
95       color[3] = colors.Get(offset + 3);
96 
97       vtkm::Vec<Precision, 3> lightDir = LightPosition - intersection;
98       vtkm::Vec<Precision, 3> viewDir = CameraPosition - LookAt;
99       vtkm::Normalize(lightDir);
100       vtkm::Normalize(viewDir);
101       //Diffuse lighting
102       Precision cosTheta = vtkm::dot(normal, lightDir);
103       //clamp tp [0,1]
104       const Precision zero = 0.f;
105       const Precision one = 1.f;
106       cosTheta = vtkm::Min(vtkm::Max(cosTheta, zero), one);
107       //Specular lighting
108       vtkm::Vec<Precision, 3> reflect = 2.f * vtkm::dot(lightDir, normal) * normal - lightDir;
109       vtkm::Normalize(reflect);
110       Precision cosPhi = vtkm::dot(reflect, viewDir);
111       Precision specularConstant =
112         vtkm::Pow(vtkm::Max(cosPhi, zero), static_cast<Precision>(SpecularExponent));
113       vtkm::Int32 colorMapSize = static_cast<vtkm::Int32>(colorMap.GetNumberOfValues());
114       vtkm::Int32 colorIdx = vtkm::Int32(scalar * Precision(colorMapSize - 1));
115 
116       // clamp color index
117       colorIdx = vtkm::Max(0, colorIdx);
118       colorIdx = vtkm::Min(colorMapSize - 1, colorIdx);
119       color = colorMap.Get(colorIdx);
120 
121       color[0] *= vtkm::Min(
122         LightAbmient[0] + LightDiffuse[0] * cosTheta + LightSpecular[0] * specularConstant, one);
123       color[1] *= vtkm::Min(
124         LightAbmient[1] + LightDiffuse[1] * cosTheta + LightSpecular[1] * specularConstant, one);
125       color[2] *= vtkm::Min(
126         LightAbmient[2] + LightDiffuse[2] * cosTheta + LightSpecular[2] * specularConstant, one);
127 
128       colors.Set(offset + 0, color[0]);
129       colors.Set(offset + 1, color[1]);
130       colors.Set(offset + 2, color[2]);
131       colors.Set(offset + 3, color[3]);
132     }
133 
134   }; //class Shade
135 
136   class MapScalarToColor : public vtkm::worklet::WorkletMapField
137   {
138   public:
139     VTKM_CONT
MapScalarToColor()140     MapScalarToColor() {}
141 
142     using ControlSignature = void(FieldIn, FieldIn, WholeArrayInOut, WholeArrayIn);
143     using ExecutionSignature = void(_1, _2, _3, _4, WorkIndex);
144 
145     template <typename ColorPortalType, typename Precision, typename ColorMapPortalType>
operator ()(const vtkm::Id & hitIdx,const Precision & scalar,ColorPortalType & colors,ColorMapPortalType colorMap,const vtkm::Id & idx) const146     VTKM_EXEC void operator()(const vtkm::Id& hitIdx,
147                               const Precision& scalar,
148                               ColorPortalType& colors,
149                               ColorMapPortalType colorMap,
150                               const vtkm::Id& idx) const
151     {
152 
153       if (hitIdx < 0)
154       {
155         return;
156       }
157 
158       vtkm::Vec<Precision, 4> color;
159       vtkm::Id offset = idx * 4;
160 
161       vtkm::Int32 colorMapSize = static_cast<vtkm::Int32>(colorMap.GetNumberOfValues());
162       vtkm::Int32 colorIdx = vtkm::Int32(scalar * Precision(colorMapSize - 1));
163 
164       // clamp color index
165       colorIdx = vtkm::Max(0, colorIdx);
166       colorIdx = vtkm::Min(colorMapSize - 1, colorIdx);
167       color = colorMap.Get(colorIdx);
168 
169       colors.Set(offset + 0, color[0]);
170       colors.Set(offset + 1, color[1]);
171       colors.Set(offset + 2, color[2]);
172       colors.Set(offset + 3, color[3]);
173     }
174 
175   }; //class MapScalarToColor
176 
177   template <typename Precision>
run(Ray<Precision> & rays,vtkm::cont::ArrayHandle<vtkm::Vec4f_32> & colorMap,const vtkm::rendering::raytracing::Camera & camera,bool shade)178   VTKM_CONT void run(Ray<Precision>& rays,
179                      vtkm::cont::ArrayHandle<vtkm::Vec4f_32>& colorMap,
180                      const vtkm::rendering::raytracing::Camera& camera,
181                      bool shade)
182   {
183     if (shade)
184     {
185       // TODO: support light positions
186       vtkm::Vec3f_32 scale(2, 2, 2);
187       vtkm::Vec3f_32 lightPosition = camera.GetPosition() + scale * camera.GetUp();
188       vtkm::worklet::DispatcherMapField<Shade>(
189         Shade(lightPosition, camera.GetPosition(), camera.GetLookAt()))
190         .Invoke(rays.HitIdx,
191                 rays.Scalar,
192                 rays.Normal,
193                 rays.Intersection,
194                 rays.Buffers.at(0).Buffer,
195                 colorMap);
196     }
197     else
198     {
199       vtkm::worklet::DispatcherMapField<MapScalarToColor>(MapScalarToColor())
200         .Invoke(rays.HitIdx, rays.Scalar, rays.Buffers.at(0).Buffer, colorMap);
201     }
202   }
203 }; // class SurfaceColor
204 
205 } // namespace detail
206 
RayTracer()207 RayTracer::RayTracer()
208   : NumberOfShapes(0)
209   , Shade(true)
210 {
211 }
212 
~RayTracer()213 RayTracer::~RayTracer()
214 {
215   Clear();
216 }
217 
GetCamera()218 Camera& RayTracer::GetCamera()
219 {
220   return camera;
221 }
222 
223 
AddShapeIntersector(std::shared_ptr<ShapeIntersector> intersector)224 void RayTracer::AddShapeIntersector(std::shared_ptr<ShapeIntersector> intersector)
225 {
226   NumberOfShapes += intersector->GetNumberOfShapes();
227   Intersectors.push_back(intersector);
228 }
229 
SetField(const vtkm::cont::Field & scalarField,const vtkm::Range & scalarRange)230 void RayTracer::SetField(const vtkm::cont::Field& scalarField, const vtkm::Range& scalarRange)
231 {
232   ScalarField = scalarField;
233   ScalarRange = scalarRange;
234 }
235 
SetColorMap(const vtkm::cont::ArrayHandle<vtkm::Vec4f_32> & colorMap)236 void RayTracer::SetColorMap(const vtkm::cont::ArrayHandle<vtkm::Vec4f_32>& colorMap)
237 {
238   ColorMap = colorMap;
239 }
240 
Render(Ray<vtkm::Float32> & rays)241 void RayTracer::Render(Ray<vtkm::Float32>& rays)
242 {
243   RenderOnDevice(rays);
244 }
245 
Render(Ray<vtkm::Float64> & rays)246 void RayTracer::Render(Ray<vtkm::Float64>& rays)
247 {
248   RenderOnDevice(rays);
249 }
250 
SetShadingOn(bool on)251 void RayTracer::SetShadingOn(bool on)
252 {
253   Shade = on;
254 }
255 
GetNumberOfShapes() const256 vtkm::Id RayTracer::GetNumberOfShapes() const
257 {
258   return NumberOfShapes;
259 }
260 
Clear()261 void RayTracer::Clear()
262 {
263   Intersectors.clear();
264 }
265 
266 template <typename Precision>
RenderOnDevice(Ray<Precision> & rays)267 void RayTracer::RenderOnDevice(Ray<Precision>& rays)
268 {
269   using Timer = vtkm::cont::Timer;
270 
271   Logger* logger = Logger::GetInstance();
272   Timer renderTimer;
273   renderTimer.Start();
274   vtkm::Float64 time = 0.;
275   logger->OpenLogEntry("ray_tracer");
276   logger->AddLogData("device", GetDeviceString());
277 
278   logger->AddLogData("shapes", NumberOfShapes);
279   logger->AddLogData("num_rays", rays.NumRays);
280 
281   size_t numShapes = Intersectors.size();
282   if (NumberOfShapes > 0)
283   {
284     Timer timer;
285     timer.Start();
286 
287     for (size_t i = 0; i < numShapes; ++i)
288     {
289       Intersectors[i]->IntersectRays(rays);
290       time = timer.GetElapsedTime();
291       logger->AddLogData("intersect", time);
292 
293       timer.Start();
294       Intersectors[i]->IntersectionData(rays, ScalarField, ScalarRange);
295       time = timer.GetElapsedTime();
296       logger->AddLogData("intersection_data", time);
297       timer.Start();
298 
299       // Calculate the color at the intersection  point
300       detail::SurfaceColor surfaceColor;
301       surfaceColor.run(rays, ColorMap, camera, this->Shade);
302 
303       time = timer.GetElapsedTime();
304       logger->AddLogData("shade", time);
305     }
306   }
307 
308   time = renderTimer.GetElapsedTime();
309   logger->CloseLogEntry(time);
310 } // RenderOnDevice
311 }
312 }
313 } // namespace vtkm::rendering::raytracing
314