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