refactoring ray tracing and adding new renderer

This commit is contained in:
Matt Larsen 2017-06-17 14:28:45 -07:00
parent f69ead4bb0
commit 630e871ea7
41 changed files with 10573 additions and 2262 deletions

@ -32,12 +32,14 @@ set(headers
Color.h
ColorBarAnnotation.h
ColorTable.h
ConnectivityProxy.h
DecodePNG.h
MatrixHelpers.h
Scene.h
Mapper.h
MapperRayTracer.h
MapperVolume.h
MapperConnectivity.h
TextAnnotation.h
TextAnnotationBillboard.h
TextAnnotationScreen.h
@ -63,10 +65,12 @@ set(sources
Color.cxx
ColorBarAnnotation.cxx
ColorTable.cxx
ConnectivityProxy.cxx
DecodePNG.cxx
Mapper.cxx
MapperRayTracer.cxx
MapperVolume.cxx
MapperConnectivity.cxx
Scene.cxx
TextAnnotation.cxx
TextAnnotationBillboard.cxx
@ -78,7 +82,11 @@ set(sources
WorldAnnotator.cxx
internal/RunTriangulator.cxx
raytracing/Ray.cxx
raytracing/BoundingVolumeHierarchy.cxx
raytracing/Camera.cxx
raytracing/ChannelBuffer.cxx
raytracing/Logger.cxx
raytracing/RayTracer.cxx
)
set(opengl_headers
@ -115,6 +123,11 @@ set(osmesa_sources
# compiled with a device-specific compiler (like CUDA).
set(device_sources
CanvasRayTracer.cxx
ConnectivityProxy.cxx
raytracing/BoundingVolumeHierarchy.cxx
raytracing/Camera.cxx
raytracing/ChannelBuffer.cxx
raytracing/RayTracer.cxx
)
#-----------------------------------------------------------------------------

@ -24,6 +24,7 @@
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/rendering/Canvas.h>
#include <vtkm/rendering/Color.h>
#include <vtkm/rendering/raytracing/Ray.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/WorkletMapField.h>
@ -85,6 +86,101 @@ struct ClearBuffersInvokeFunctor
}
};
class SurfaceConverter : public vtkm::worklet::WorkletMapField
{
vtkm::Float32 Proj22;
vtkm::Float32 Proj23;
vtkm::Float32 Proj32;
public:
VTKM_CONT
SurfaceConverter(const vtkm::Matrix<vtkm::Float32, 4, 4> projMat)
{
Proj22 = projMat[2][2];
Proj23 = projMat[2][3];
Proj32 = projMat[3][2];
}
typedef void ControlSignature(FieldIn<>, WholeArrayIn<>, FieldIn<>, ExecObject, ExecObject);
typedef void ExecutionSignature(_1, _2, _3, _4, _5, WorkIndex);
template <typename Precision, typename ColorPortalType>
VTKM_EXEC void operator()(
const vtkm::Id& pixelIndex,
ColorPortalType& colorBufferIn,
const Precision& inDepth,
vtkm::exec::ExecutionWholeArray<vtkm::Float32>& depthBuffer,
vtkm::exec::ExecutionWholeArray<vtkm::Vec<vtkm::Float32, 4>>& colorBuffer,
const vtkm::Id& index) const
{
vtkm::Float32 depth = (Proj22 + Proj23 / (-static_cast<vtkm::Float32>(inDepth))) / Proj32;
depth = 0.5f * depth + 0.5f;
vtkm::Vec<vtkm::Float32, 4> color;
color[0] = static_cast<vtkm::Float32>(colorBufferIn.Get(index * 4 + 0));
color[1] = static_cast<vtkm::Float32>(colorBufferIn.Get(index * 4 + 1));
color[2] = static_cast<vtkm::Float32>(colorBufferIn.Get(index * 4 + 2));
color[3] = static_cast<vtkm::Float32>(colorBufferIn.Get(index * 4 + 3));
depthBuffer.Set(pixelIndex, depth);
colorBuffer.Set(pixelIndex, color);
}
}; //class SurfaceConverter
template <typename Precision>
struct WriteFunctor
{
protected:
vtkm::rendering::CanvasRayTracer* Canvas;
const vtkm::cont::ArrayHandle<Precision>& Distances;
const vtkm::cont::ArrayHandle<Precision>& Colors;
const vtkm::cont::ArrayHandle<vtkm::Id>& PixelIds;
const vtkm::rendering::Camera& CameraView;
public:
VTKM_CONT
WriteFunctor(vtkm::rendering::CanvasRayTracer* canvas,
const vtkm::cont::ArrayHandle<Precision>& distances,
const vtkm::cont::ArrayHandle<Precision>& colors,
const vtkm::cont::ArrayHandle<vtkm::Id>& pixelIds,
const vtkm::rendering::Camera& camera)
: Canvas(canvas)
, Distances(distances)
, Colors(colors)
, PixelIds(pixelIds)
, CameraView(camera)
{
}
template <typename Device>
VTKM_CONT bool operator()(Device)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::worklet::DispatcherMapField<SurfaceConverter, Device>(
SurfaceConverter(
this->CameraView.CreateProjectionMatrix(Canvas->GetWidth(), Canvas->GetHeight())))
.Invoke(
PixelIds,
Colors,
Distances,
vtkm::exec::ExecutionWholeArray<vtkm::Float32>(Canvas->GetDepthBuffer()),
vtkm::exec::ExecutionWholeArray<vtkm::Vec<vtkm::Float32, 4>>(Canvas->GetColorBuffer()));
return true;
}
};
template <typename Precision>
VTKM_CONT void WriteToCanvas(const vtkm::cont::ArrayHandle<vtkm::Id>& pixelIds,
const vtkm::cont::ArrayHandle<Precision>& distances,
const vtkm::cont::ArrayHandle<Precision>& colors,
const vtkm::rendering::Camera& camera,
vtkm::rendering::CanvasRayTracer* canvas)
{
WriteFunctor<Precision> functor(canvas, distances, colors, pixelIds, camera);
vtkm::cont::TryExecute(functor);
//Force the transfer so the vectors contain data from device
canvas->GetColorBuffer().GetPortalControl().Get(0);
canvas->GetDepthBuffer().GetPortalControl().Get(0);
}
} // namespace internal
CanvasRayTracer::CanvasRayTracer(vtkm::Id width, vtkm::Id height)
@ -119,6 +215,22 @@ void CanvasRayTracer::Clear()
this->GetBackgroundColor(), this->GetColorBuffer(), this->GetDepthBuffer()));
}
void CanvasRayTracer::WriteToCanvas(const vtkm::cont::ArrayHandle<vtkm::Id>& pixelIds,
const vtkm::cont::ArrayHandle<vtkm::Float32>& distances,
const vtkm::cont::ArrayHandle<vtkm::Float32>& colors,
const vtkm::rendering::Camera& camera)
{
internal::WriteToCanvas(pixelIds, distances, colors, camera, this);
}
void CanvasRayTracer::WriteToCanvas(const vtkm::cont::ArrayHandle<vtkm::Id>& pixelIds,
const vtkm::cont::ArrayHandle<vtkm::Float64>& distances,
const vtkm::cont::ArrayHandle<vtkm::Float64>& colors,
const vtkm::rendering::Camera& camera)
{
internal::WriteToCanvas(pixelIds, distances, colors, camera, this);
}
vtkm::rendering::Canvas* CanvasRayTracer::NewCopy() const
{
return new vtkm::rendering::CanvasRayTracer(*this);

@ -23,7 +23,6 @@
#include <vtkm/rendering/vtkm_rendering_export.h>
#include <vtkm/rendering/Canvas.h>
namespace vtkm
{
namespace rendering
@ -46,6 +45,16 @@ public:
vtkm::rendering::Canvas* NewCopy() const VTKM_OVERRIDE;
void WriteToCanvas(const vtkm::cont::ArrayHandle<vtkm::Id>& pixelIds,
const vtkm::cont::ArrayHandle<vtkm::Float32>& distances,
const vtkm::cont::ArrayHandle<vtkm::Float32>& colors,
const vtkm::rendering::Camera& camera);
void WriteToCanvas(const vtkm::cont::ArrayHandle<vtkm::Id>& pixelIds,
const vtkm::cont::ArrayHandle<vtkm::Float64>& distances,
const vtkm::cont::ArrayHandle<vtkm::Float64>& colors,
const vtkm::rendering::Camera& camera);
void AddLine(const vtkm::Vec<vtkm::Float64, 2>& point0,
const vtkm::Vec<vtkm::Float64, 2>& point1,
vtkm::Float32 linewidth,
@ -55,6 +64,7 @@ public:
const vtkm::rendering::ColorTable& colorTable,
bool horizontal) const VTKM_OVERRIDE;
void AddText(const vtkm::Vec<vtkm::Float32, 2>& position,
vtkm::Float32 scale,
vtkm::Float32 angle,

@ -20,6 +20,8 @@
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/Math.h>
#include <string>
#include <vector>
@ -80,6 +82,11 @@ bool ColorTable::GetSmooth() const
return this->Internals->Smooth;
}
void ColorTable::SetSmooth(bool smooth)
{
this->Internals->Smooth = smooth;
}
void ColorTable::Sample(int numSamples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& colors) const
{
@ -220,6 +227,28 @@ void ColorTable::Clear()
this->Internals->Smooth = false;
}
ColorTable ColorTable::CorrectOpacity(const vtkm::Float32& factor) const
{
ColorTable corrected;
corrected.SetSmooth(this->Internals->Smooth);
size_t rgbSize = this->Internals->RGBPoints.size();
for (size_t i = 0; i < rgbSize; ++i)
{
detail::ColorControlPoint point = this->Internals->RGBPoints.at(i);
corrected.AddControlPoint(point.Position, point.RGBA);
}
size_t alphaSize = this->Internals->AlphaPoints.size();
for (size_t i = 0; i < alphaSize; ++i)
{
detail::AlphaControlPoint point = this->Internals->AlphaPoints.at(i);
vtkm::Float32 alpha = 1.f - vtkm::Pow((1.f - point.AlphaValue), factor);
corrected.AddAlphaControlPoint(point.Position, alpha);
}
return corrected;
}
void ColorTable::Reverse()
{
std::shared_ptr<detail::ColorTableInternals> oldInternals = this->Internals;

@ -62,6 +62,8 @@ public:
bool GetSmooth() const;
void SetSmooth(bool smooth);
void Sample(int numSamples, vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& colors) const;
vtkm::rendering::Color MapRGB(vtkm::Float32 scalar) const;
@ -72,6 +74,8 @@ public:
void Reverse();
ColorTable CorrectOpacity(const vtkm::Float32& factor) const;
void AddControlPoint(vtkm::Float32 position, const vtkm::rendering::Color& color);
void AddControlPoint(vtkm::Float32 position,

@ -0,0 +1,341 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <cstdlib>
#include <typeinfo>
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/ConnectivityProxy.h>
#include <vtkm/rendering/Mapper.h>
#include <vtkm/rendering/raytracing/ConnectivityTracerFactory.h>
#include <vtkm/rendering/raytracing/Logger.h>
namespace vtkm
{
namespace rendering
{
struct ConnectivityProxy::InternalsType
{
protected:
typedef vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>> ColorMapType;
typedef vtkm::rendering::raytracing::ConnectivityBase BaseType;
BaseType* Tracer;
vtkm::cont::Field ScalarField;
vtkm::cont::Field EmissionField;
vtkm::cont::DynamicCellSet Cells;
vtkm::cont::CoordinateSystem Coords;
RenderMode Mode;
vtkm::Bounds SpatialBounds;
ColorMapType ColorMap;
vtkm::cont::DataSet Dataset;
vtkm::Range ScalarRange;
struct BoundsFunctor
{
vtkm::rendering::ConnectivityProxy::InternalsType* Internals;
const vtkm::cont::CoordinateSystem& Coordinates;
VTKM_CONT
BoundsFunctor(vtkm::rendering::ConnectivityProxy::InternalsType* self,
const vtkm::cont::CoordinateSystem& coordinates)
: Internals(self)
, Coordinates(coordinates)
{
}
template <typename Device>
VTKM_CONT bool operator()(Device)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
Internals->SpatialBounds = Internals->Coords.GetBounds(Device());
return true;
}
};
public:
InternalsType(vtkm::cont::DataSet& dataSet)
{
Dataset = dataSet;
Cells = dataSet.GetCellSet();
Coords = dataSet.GetCoordinateSystem();
Mode = VOLUME_MODE;
//
// Just grab a default scalar field
//
this->SetScalarField(Dataset.GetField(0).GetName());
Tracer = raytracing::ConnectivityTracerFactory::CreateTracer(Cells, Coords);
}
~InternalsType() { delete Tracer; }
void SetSampleDistance(const vtkm::Float32& distance)
{
if (Mode != VOLUME_MODE)
{
std::cout << "Volume Tracer Error: must set volume mode before setting sample dist\n";
return;
}
Tracer->SetSampleDistance(distance);
}
VTKM_CONT
void SetRenderMode(RenderMode mode) { Mode = mode; }
VTKM_CONT
RenderMode GetRenderMode() { return Mode; }
VTKM_CONT
void SetScalarField(const std::string& fieldName)
{
ScalarField = Dataset.GetField(fieldName);
const vtkm::cont::ArrayHandle<vtkm::Range> range = this->ScalarField.GetRange();
ScalarRange = range.GetPortalConstControl().Get(0);
}
VTKM_CONT
void SetColorMap(vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& colormap)
{
Tracer->SetColorMap(colormap);
}
VTKM_CONT
void SetCompositeBackground(bool on) { Tracer->SetCompositeBackground(on); }
VTKM_CONT
void SetEmissionField(const std::string& fieldName)
{
if (Mode != ENERGY_MODE)
{
std::cout << "Volume Tracer Error: must set energy mode before setting emission field\n";
return;
}
EmissionField = Dataset.GetField(fieldName);
}
VTKM_CONT
vtkm::Bounds GetSpatialBounds() const { return SpatialBounds; }
VTKM_CONT
vtkm::Range GetScalarRange() const { return ScalarRange; }
VTKM_CONT
void SetScalarRange(const vtkm::Range& range) { ScalarRange = range; }
VTKM_CONT
void Trace(vtkm::rendering::raytracing::Ray<vtkm::Float64>& rays)
{
if (Mode == VOLUME_MODE)
{
Tracer->SetVolumeData(this->ScalarField, this->ScalarRange);
}
else
{
Tracer->SetEnergyData(this->ScalarField, rays.Buffers.at(0).GetNumChannels());
}
Tracer->Trace(rays);
}
VTKM_CONT
void Trace(vtkm::rendering::raytracing::Ray<vtkm::Float32>& rays)
{
if (Mode == VOLUME_MODE)
{
Tracer->SetVolumeData(this->ScalarField, this->ScalarRange);
}
else
{
Tracer->SetEnergyData(this->ScalarField, rays.Buffers.at(0).GetNumChannels());
}
Tracer->Trace(rays);
}
VTKM_CONT
void Trace(const vtkm::rendering::Camera& camera, vtkm::rendering::CanvasRayTracer* canvas)
{
if (canvas == NULL)
{
std::cout << "Conn proxy: canvas is NULL\n";
return;
}
vtkm::rendering::raytracing::Camera rayCamera;
rayCamera.SetParameters(camera, *canvas);
vtkm::rendering::raytracing::Ray<vtkm::Float32> rays;
rayCamera.CreateRays(rays, this->Coords);
if (Mode == VOLUME_MODE)
{
Tracer->SetVolumeData(this->ScalarField, this->ScalarRange);
}
else
{
std::cout << "ENGERY MODE Not implementedd yet\n";
}
Tracer->Trace(rays);
canvas->WriteToCanvas(rays.PixelIdx, rays.Distance, rays.Buffers.at(0).Buffer, camera);
}
};
VTKM_CONT
ConnectivityProxy::ConnectivityProxy(vtkm::cont::DataSet& dataSet)
: Internals(new InternalsType(dataSet))
{
}
VTKM_CONT
ConnectivityProxy::ConnectivityProxy(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField)
{
vtkm::cont::DataSet dataset;
dataset.AddCellSet(cellset);
dataset.AddCoordinateSystem(coords);
dataset.AddField(scalarField);
Internals = std::shared_ptr<InternalsType>(new InternalsType(dataset));
}
VTKM_CONT
ConnectivityProxy::~ConnectivityProxy()
{
}
VTKM_CONT
ConnectivityProxy::ConnectivityProxy()
{
}
VTKM_CONT
void ConnectivityProxy::SetSampleDistance(const vtkm::Float32& distance)
{
Internals->SetSampleDistance(distance);
}
VTKM_CONT
void ConnectivityProxy::SetRenderMode(RenderMode mode)
{
Internals->SetRenderMode(mode);
}
VTKM_CONT
void ConnectivityProxy::SetScalarField(const std::string& fieldName)
{
Internals->SetScalarField(fieldName);
}
VTKM_CONT
void ConnectivityProxy::SetColorMap(vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& colormap)
{
Internals->SetColorMap(colormap);
}
VTKM_CONT
void ConnectivityProxy::SetEmissionField(const std::string& fieldName)
{
Internals->SetEmissionField(fieldName);
}
VTKM_CONT
vtkm::Bounds ConnectivityProxy::GetSpatialBounds()
{
return Internals->GetSpatialBounds();
}
VTKM_CONT
vtkm::Range ConnectivityProxy::GetScalarRange()
{
return Internals->GetScalarRange();
}
VTKM_CONT
void ConnectivityProxy::SetCompositeBackground(bool on)
{
return Internals->SetCompositeBackground(on);
}
VTKM_CONT
void ConnectivityProxy::SetScalarRange(const vtkm::Range& range)
{
Internals->SetScalarRange(range);
}
VTKM_CONT
void ConnectivityProxy::Trace(vtkm::rendering::raytracing::Ray<vtkm::Float64>& rays)
{
raytracing::Logger* logger = raytracing::Logger::GetInstance();
logger->OpenLogEntry("connectivity_trace_64");
if (Internals->GetRenderMode() == VOLUME_MODE)
{
logger->AddLogData("volume_mode", "true");
}
else
{
logger->AddLogData("volume_mode", "false");
}
Internals->Trace(rays);
logger->CloseLogEntry(-1.0);
}
VTKM_CONT
void ConnectivityProxy::Trace(vtkm::rendering::raytracing::Ray<vtkm::Float32>& rays)
{
raytracing::Logger* logger = raytracing::Logger::GetInstance();
logger->OpenLogEntry("connectivity_trace_32");
if (Internals->GetRenderMode() == VOLUME_MODE)
{
logger->AddLogData("volume_mode", "true");
}
else
{
logger->AddLogData("volume_mode", "false");
}
Internals->Trace(rays);
logger->CloseLogEntry(-1.0);
}
VTKM_CONT
void ConnectivityProxy::Trace(const vtkm::rendering::Camera& camera,
vtkm::rendering::CanvasRayTracer* canvas)
{
raytracing::Logger* logger = raytracing::Logger::GetInstance();
logger->OpenLogEntry("connectivity_trace_32");
logger->AddLogData("volume_mode", "true");
Internals->Trace(camera, canvas);
logger->CloseLogEntry(-1.0);
}
}
} // namespace vtkm::rendering

@ -0,0 +1,81 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_rendering_ConnectivityProxy_h
#define vtk_m_rendering_ConnectivityProxy_h
#include <cstdlib>
#include <memory>
#include <typeinfo>
#include <vtkm/cont/DataSet.h>
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/Mapper.h>
#include <vtkm/rendering/View.h>
#include <vtkm/rendering/raytracing/Camera.h>
#include <vtkm/rendering/raytracing/Ray.h>
namespace vtkm
{
namespace rendering
{
class VTKM_RENDERING_EXPORT ConnectivityProxy
{
public:
ConnectivityProxy(vtkm::cont::DataSet& dataset);
ConnectivityProxy(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField);
~ConnectivityProxy();
enum RenderMode
{
VOLUME_MODE,
ENERGY_MODE
};
void SetRenderMode(RenderMode mode);
void SetSampleDistance(const vtkm::Float32&);
void SetCanvas(vtkm::rendering::Canvas* canvas);
void SetScalarField(const std::string& fieldName);
void SetEmissionField(const std::string& fieldName);
void SetCamera(const vtkm::rendering::Camera& camera);
void SetScalarRange(const vtkm::Range& range);
void SetColorMap(vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& colormap);
void SetCompositeBackground(bool on);
vtkm::Bounds GetSpatialBounds();
vtkm::Range GetScalarRange();
void Trace(const vtkm::rendering::Camera& camera, vtkm::rendering::CanvasRayTracer* canvas);
void Trace(vtkm::rendering::raytracing::Ray<vtkm::Float64>& rays);
void Trace(vtkm::rendering::raytracing::Ray<vtkm::Float32>& rays);
protected:
struct InternalsType;
struct BoundsFunctor;
std::shared_ptr<InternalsType> Internals;
private:
// Do not allow the default constructor
ConnectivityProxy();
};
}
} //namespace vtkm::rendering
#endif //vtk_m_rendering_SceneRendererVolume_h

@ -0,0 +1,107 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/ConnectivityProxy.h>
#include <vtkm/rendering/Mapper.h>
#include <vtkm/rendering/MapperConnectivity.h>
#include <vtkm/rendering/View.h>
#include <vtkm/rendering/raytracing/Camera.h>
#include <vtkm/rendering/raytracing/ConnectivityTracerFactory.h>
#include <cstdlib>
namespace vtkm
{
namespace rendering
{
VTKM_CONT
MapperConnectivity::MapperConnectivity()
{
CanvasRT = NULL;
SampleDistance = -1;
}
VTKM_CONT
MapperConnectivity::~MapperConnectivity()
{
}
VTKM_CONT
void MapperConnectivity::SetSampleDistance(const vtkm::Float32& distance)
{
SampleDistance = distance;
}
VTKM_CONT
void MapperConnectivity::SetCanvas(Canvas* canvas)
{
if (canvas != NULL)
{
CanvasRT = dynamic_cast<CanvasRayTracer*>(canvas);
if (CanvasRT == NULL)
{
throw vtkm::cont::ErrorBadValue("Volume Render: bad canvas type. Must be CanvasRayTracer");
}
}
}
vtkm::rendering::Canvas* MapperConnectivity::GetCanvas() const
{
return CanvasRT;
}
VTKM_CONT
void MapperConnectivity::RenderCells(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::ColorTable& vtkmNotUsed(colorTable),
const vtkm::rendering::Camera& camera,
const vtkm::Range& vtkmNotUsed(scalarRange))
{
vtkm::rendering::ConnectivityProxy tracerProxy(cellset, coords, scalarField);
if (SampleDistance != -1.f)
{
tracerProxy.SetSampleDistance(SampleDistance);
}
tracerProxy.SetColorMap(ColorMap);
tracerProxy.Trace(camera, CanvasRT);
}
void MapperConnectivity::StartScene()
{
// Nothing needs to be done.
}
void MapperConnectivity::EndScene()
{
// Nothing needs to be done.
}
vtkm::rendering::Mapper* MapperConnectivity::NewCopy() const
{
return new vtkm::rendering::MapperConnectivity(*this);
}
}
} // namespace vtkm::rendering

@ -0,0 +1,64 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_rendering_MapperConnectivity_h
#define vtk_m_rendering_MapperConnectivity_h
#include <cstdlib>
#include <typeinfo>
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/Mapper.h>
#include <vtkm/rendering/View.h>
namespace vtkm
{
namespace rendering
{
class VTKM_RENDERING_EXPORT MapperConnectivity : public Mapper
{
public:
MapperConnectivity();
~MapperConnectivity();
void SetSampleDistance(const vtkm::Float32&);
void SetCanvas(vtkm::rendering::Canvas* canvas) VTKM_OVERRIDE;
virtual vtkm::rendering::Canvas* GetCanvas() const VTKM_OVERRIDE;
virtual void RenderCells(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::ColorTable&, //colorTable
const vtkm::rendering::Camera& camera,
const vtkm::Range& scalarRange) VTKM_OVERRIDE;
virtual void StartScene() VTKM_OVERRIDE;
virtual void EndScene() VTKM_OVERRIDE;
vtkm::rendering::Mapper* NewCopy() const VTKM_OVERRIDE;
void CreateDefaultView();
protected:
vtkm::Float32 SampleDistance;
CanvasRayTracer* CanvasRT;
};
}
} //namespace vtkm::rendering
#endif //vtk_m_rendering_SceneRendererVolume_h

@ -26,6 +26,7 @@
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/rendering/internal/RunTriangulator.h>
#include <vtkm/rendering/raytracing/Camera.h>
#include <vtkm/rendering/raytracing/Logger.h>
#include <vtkm/rendering/raytracing/RayTracer.h>
namespace vtkm
@ -36,41 +37,15 @@ namespace rendering
struct MapperRayTracer::InternalsType
{
vtkm::rendering::CanvasRayTracer* Canvas;
std::shared_ptr<vtkm::cont::internal::SimplePolymorphicContainerBase> RayTracerContainer;
vtkm::rendering::raytracing::RayTracer Tracer;
vtkm::rendering::raytracing::Camera RayCamera;
vtkm::rendering::raytracing::Ray<vtkm::Float32> Rays;
VTKM_CONT
InternalsType()
: Canvas(nullptr)
{
}
template <typename Device>
VTKM_CONT vtkm::rendering::raytracing::RayTracer<Device>* GetRayTracer(Device)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
typedef vtkm::rendering::raytracing::RayTracer<Device> RayTracerType;
typedef vtkm::cont::internal::SimplePolymorphicContainer<RayTracerType> ContainerType;
RayTracerType* tracer = nullptr;
if (this->RayTracerContainer)
{
ContainerType* container = dynamic_cast<ContainerType*>(this->RayTracerContainer.get());
if (container)
{
tracer = &container->Item;
}
}
if (tracer == nullptr)
{
ContainerType* container =
new vtkm::cont::internal::SimplePolymorphicContainer<RayTracerType>;
tracer = &container->Item;
this->RayTracerContainer.reset(container);
}
return tracer;
}
};
MapperRayTracer::MapperRayTracer()
@ -103,60 +78,6 @@ vtkm::rendering::Canvas* MapperRayTracer::GetCanvas() const
return this->Internals->Canvas;
}
struct MapperRayTracer::RenderFunctor
{
vtkm::rendering::MapperRayTracer* Self;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> TriangleIndices;
vtkm::Id NumberOfTriangles;
vtkm::cont::CoordinateSystem Coordinates;
vtkm::cont::Field ScalarField;
vtkm::rendering::Camera Camera;
vtkm::Range ScalarRange;
VTKM_CONT
RenderFunctor(vtkm::rendering::MapperRayTracer* self,
const vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>>& indices,
vtkm::Id numberOfTriangles,
const vtkm::cont::CoordinateSystem& coordinates,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::Camera& camera,
const vtkm::Range& scalarRange)
: Self(self)
, TriangleIndices(indices)
, NumberOfTriangles(numberOfTriangles)
, Coordinates(coordinates)
, ScalarField(scalarField)
, Camera(camera)
, ScalarRange(scalarRange)
{
}
template <typename Device>
bool operator()(Device)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::rendering::raytracing::RayTracer<Device>* tracer =
this->Self->Internals->GetRayTracer(Device());
tracer->GetCamera().SetParameters(this->Camera, *this->Self->Internals->Canvas);
vtkm::Bounds dataBounds = this->Coordinates.GetBounds();
tracer->SetData(this->Coordinates.GetData(),
this->TriangleIndices,
this->ScalarField,
this->NumberOfTriangles,
this->ScalarRange,
dataBounds);
tracer->SetColorMap(this->Self->ColorMap);
tracer->SetBackgroundColor(this->Self->Internals->Canvas->GetBackgroundColor().Components);
tracer->Render(this->Self->Internals->Canvas);
return true;
}
};
void MapperRayTracer::RenderCells(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField,
@ -164,12 +85,41 @@ void MapperRayTracer::RenderCells(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::rendering::Camera& camera,
const vtkm::Range& scalarRange)
{
raytracing::Logger* logger = raytracing::Logger::GetInstance();
logger->OpenLogEntry("mapper_ray_tracer");
vtkm::cont::Timer<> tot_timer;
vtkm::cont::Timer<> timer;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> indices;
vtkm::Id numberOfTriangles;
vtkm::rendering::internal::RunTriangulator(cellset, indices, numberOfTriangles);
RenderFunctor functor(this, indices, numberOfTriangles, coords, scalarField, camera, scalarRange);
vtkm::cont::TryExecute(functor);
vtkm::rendering::internal::RunTriangulator(cellset, indices, numberOfTriangles);
vtkm::Float64 time = timer.GetElapsedTime();
logger->AddLogData("triangulator", time);
vtkm::rendering::raytracing::Camera& cam = this->Internals->Tracer.GetCamera();
cam.SetParameters(camera, *this->Internals->Canvas);
this->Internals->RayCamera.SetParameters(camera, *this->Internals->Canvas);
this->Internals->RayCamera.CreateRays(this->Internals->Rays, coords);
vtkm::Bounds dataBounds = coords.GetBounds();
this->Internals->Tracer.SetData(
coords.GetData(), indices, scalarField, numberOfTriangles, scalarRange, dataBounds);
this->Internals->Tracer.SetColorMap(this->ColorMap);
this->Internals->Tracer.SetBackgroundColor(
this->Internals->Canvas->GetBackgroundColor().Components);
this->Internals->Tracer.Render(this->Internals->Rays);
timer.Reset();
this->Internals->Canvas->WriteToCanvas(this->Internals->Rays.PixelIdx,
this->Internals->Rays.Distance,
this->Internals->Rays.Buffers.at(0).Buffer,
camera);
time = timer.GetElapsedTime();
logger->AddLogData("write_to_canvas", time);
time = tot_timer.GetElapsedTime();
logger->CloseLogEntry(time);
}
void MapperRayTracer::StartScene()

@ -20,7 +20,6 @@
#include <vtkm/rendering/MapperVolume.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/cont/internal/SimplePolymorphicContainer.h>
@ -29,8 +28,10 @@
#include <vtkm/rendering/internal/RunTriangulator.h>
#include <vtkm/rendering/raytracing/Camera.h>
#include <vtkm/rendering/raytracing/Logger.h>
#include <vtkm/rendering/raytracing/VolumeRendererStructured.h>
#include <sstream>
#include <typeinfo>
#define DEFAULT_SAMPLE_DISTANCE -1.f
@ -45,8 +46,6 @@ struct MapperVolume::InternalsType
vtkm::rendering::CanvasRayTracer* Canvas;
vtkm::Float32 SampleDistance;
bool CompositeBackground;
vtkm::cont::RuntimeDeviceTracker DeviceTracker;
std::shared_ptr<vtkm::cont::internal::SimplePolymorphicContainerBase> RayTracerContainer;
VTKM_CONT
InternalsType()
@ -55,34 +54,6 @@ struct MapperVolume::InternalsType
, CompositeBackground(true)
{
}
template <typename Device>
VTKM_CONT vtkm::rendering::raytracing::VolumeRendererStructured<Device>* GetRayTracer(Device)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
typedef vtkm::rendering::raytracing::VolumeRendererStructured<Device> RayTracerType;
typedef vtkm::cont::internal::SimplePolymorphicContainer<RayTracerType> ContainerType;
RayTracerType* tracer = nullptr;
if (this->RayTracerContainer)
{
ContainerType* container = dynamic_cast<ContainerType*>(this->RayTracerContainer.get());
if (container)
{
tracer = &container->Item;
}
}
if (tracer == nullptr)
{
ContainerType* container =
new vtkm::cont::internal::SimplePolymorphicContainer<RayTracerType>;
tracer = &container->Item;
this->RayTracerContainer.reset(container);
}
return tracer;
}
};
MapperVolume::MapperVolume()
@ -99,6 +70,7 @@ void MapperVolume::SetCanvas(vtkm::rendering::Canvas* canvas)
if (canvas != nullptr)
{
this->Internals->Canvas = dynamic_cast<CanvasRayTracer*>(canvas);
if (this->Internals->Canvas == nullptr)
{
throw vtkm::cont::ErrorBadValue("Ray Tracer: bad canvas type. Must be CanvasRayTracer");
@ -115,59 +87,6 @@ vtkm::rendering::Canvas* MapperVolume::GetCanvas() const
return this->Internals->Canvas;
}
struct MapperVolume::RenderFunctor
{
vtkm::rendering::MapperVolume* Self;
vtkm::cont::CellSetStructured<3> CellSet;
vtkm::cont::CoordinateSystem Coordinates;
vtkm::cont::Field ScalarField;
vtkm::rendering::Camera Camera;
vtkm::Range ScalarRange;
VTKM_CONT
RenderFunctor(vtkm::rendering::MapperVolume* self,
const vtkm::cont::CellSetStructured<3> cellSet,
const vtkm::cont::CoordinateSystem& coordinates,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::Camera& camera,
const vtkm::Range& scalarRange)
: Self(self)
, CellSet(cellSet)
, Coordinates(coordinates)
, ScalarField(scalarField)
, Camera(camera)
, ScalarRange(scalarRange)
{
}
template <typename Device>
bool operator()(Device)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::rendering::raytracing::VolumeRendererStructured<Device>* tracer =
this->Self->Internals->GetRayTracer(Device());
tracer->GetCamera().SetParameters(this->Camera, *this->Self->Internals->Canvas);
// Check to see of the sample distance was set
if (this->Self->Internals->SampleDistance != DEFAULT_SAMPLE_DISTANCE)
{
tracer->SetSampleDistance(this->Self->Internals->SampleDistance);
}
tracer->SetCompositeBackground(this->Self->Internals->CompositeBackground);
vtkm::Bounds dataBounds = this->Coordinates.GetBounds();
tracer->SetData(
this->Coordinates, this->ScalarField, dataBounds, this->CellSet, this->ScalarRange);
tracer->SetColorMap(this->Self->ColorMap);
tracer->SetBackgroundColor(this->Self->Internals->Canvas->GetBackgroundColor().Components);
tracer->Render(this->Self->Internals->Canvas);
return true;
}
};
void MapperVolume::RenderCells(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField,
@ -177,20 +96,49 @@ void MapperVolume::RenderCells(const vtkm::cont::DynamicCellSet& cellset,
{
if (!cellset.IsSameType(vtkm::cont::CellSetStructured<3>()))
{
std::cerr << "ERROR cell set type not currently supported\n";
std::stringstream msg;
std::string theType = typeid(cellset).name();
std::cerr << "Type : " << theType << std::endl;
msg << "Mapper volume: cell set type not currently supported\n";
msg << "Type : " << theType << std::endl;
throw vtkm::cont::ErrorBadValue(msg.str());
}
else
{
RenderFunctor functor(this,
cellset.Cast<vtkm::cont::CellSetStructured<3>>(),
coords,
scalarField,
camera,
scalarRange);
vtkm::cont::TryExecute(
functor, this->Internals->DeviceTracker, VTKM_DEFAULT_DEVICE_ADAPTER_LIST_TAG());
raytracing::Logger* logger = raytracing::Logger::GetInstance();
logger->OpenLogEntry("mapper_volume");
vtkm::cont::Timer<> tot_timer;
vtkm::cont::Timer<> timer;
vtkm::rendering::raytracing::VolumeRendererStructured tracer;
vtkm::rendering::raytracing::Camera rayCamera;
vtkm::rendering::raytracing::Ray<vtkm::Float32> rays;
rayCamera.SetParameters(camera, *this->Internals->Canvas);
rayCamera.CreateRays(rays, coords);
rays.Buffers.at(0).InitConst(0.f);
if (this->Internals->SampleDistance != DEFAULT_SAMPLE_DISTANCE)
{
tracer.SetSampleDistance(this->Internals->SampleDistance);
}
tracer.SetData(
coords, scalarField, cellset.Cast<vtkm::cont::CellSetStructured<3>>(), scalarRange);
tracer.SetColorMap(this->ColorMap);
tracer.SetBackgroundColor(this->Internals->Canvas->GetBackgroundColor().Components);
tracer.Render(rays);
timer.Reset();
this->Internals->Canvas->WriteToCanvas(
rays.PixelIdx, rays.Distance, rays.Buffers.at(0).Buffer, camera);
vtkm::Float64 time = timer.GetElapsedTime();
logger->AddLogData("write_to_canvas", time);
time = tot_timer.GetElapsedTime();
logger->CloseLogEntry(time);
}
}

@ -56,8 +56,6 @@ public:
private:
struct InternalsType;
std::shared_ptr<InternalsType> Internals;
struct RenderFunctor;
};
}
} //namespace vtkm::rendering

@ -0,0 +1,900 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <math.h>
#include <vtkm/Math.h>
#include <vtkm/VectorAnalysis.h>
#include <vtkm/cont/DeviceAdapter.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/exec/AtomicArray.h>
#include <vtkm/rendering/raytracing/BoundingVolumeHierarchy.h>
#include <vtkm/rendering/raytracing/Logger.h>
#include <vtkm/rendering/raytracing/MortonCodes.h>
#include <vtkm/rendering/raytracing/RayTracingTypeDefs.h>
#include <vtkm/rendering/raytracing/Worklets.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/WorkletMapField.h>
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
namespace detail
{
class LinearBVHBuilder
{
public:
class CountingIterator;
class FindAABBs;
template <typename Device>
class GatherFloat32;
template <typename Device>
class GatherVecCast;
class BVHData;
template <typename Device>
class PropagateAABBs;
template <typename Device>
class TreeBuilder;
VTKM_CONT
LinearBVHBuilder() {}
template <typename Device>
VTKM_CONT void SortAABBS(
BVHData& bvh,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>>& triangleIndices,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Int32, 4>>& outputTriangleIndices,
Device vtkmNotUsed(device));
template <typename Device>
VTKM_CONT void RunOnDevice(LinearBVH& linearBVH, Device device);
}; // class LinearBVHBuilder
class LinearBVHBuilder::CountingIterator : public vtkm::worklet::WorkletMapField
{
public:
VTKM_CONT
CountingIterator() {}
typedef void ControlSignature(FieldOut<>);
typedef void ExecutionSignature(WorkIndex, _1);
VTKM_EXEC
void operator()(const vtkm::Id& index, vtkm::Id& outId) const { outId = index; }
}; //class countingIterator
class LinearBVHBuilder::FindAABBs : public vtkm::worklet::WorkletMapField
{
public:
VTKM_CONT
FindAABBs() {}
typedef void ControlSignature(FieldIn<>,
FieldOut<>,
FieldOut<>,
FieldOut<>,
FieldOut<>,
FieldOut<>,
FieldOut<>,
WholeArrayIn<Vec3RenderingTypes>);
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6, _7, _8);
template <typename PointPortalType>
VTKM_EXEC void operator()(const vtkm::Vec<vtkm::Id, 4> indices,
vtkm::Float32& xmin,
vtkm::Float32& ymin,
vtkm::Float32& zmin,
vtkm::Float32& xmax,
vtkm::Float32& ymax,
vtkm::Float32& zmax,
const PointPortalType& points) const
{
// cast to Float32
vtkm::Vec<vtkm::Float32, 3> point;
point = static_cast<vtkm::Vec<vtkm::Float32, 3>>(points.Get(indices[1]));
xmin = point[0];
ymin = point[1];
zmin = point[2];
xmax = xmin;
ymax = ymin;
zmax = zmin;
point = static_cast<vtkm::Vec<vtkm::Float32, 3>>(points.Get(indices[2]));
xmin = vtkm::Min(xmin, point[0]);
ymin = vtkm::Min(ymin, point[1]);
zmin = vtkm::Min(zmin, point[2]);
xmax = vtkm::Max(xmax, point[0]);
ymax = vtkm::Max(ymax, point[1]);
zmax = vtkm::Max(zmax, point[2]);
point = static_cast<vtkm::Vec<vtkm::Float32, 3>>(points.Get(indices[3]));
xmin = vtkm::Min(xmin, point[0]);
ymin = vtkm::Min(ymin, point[1]);
zmin = vtkm::Min(zmin, point[2]);
xmax = vtkm::Max(xmax, point[0]);
ymax = vtkm::Max(ymax, point[1]);
zmax = vtkm::Max(zmax, point[2]);
}
}; //class FindAABBs
template <typename Device>
class LinearBVHBuilder::GatherFloat32 : public vtkm::worklet::WorkletMapField
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Float32> FloatArrayHandle;
typedef typename FloatArrayHandle::ExecutionTypes<Device>::PortalConst PortalConst;
typedef typename FloatArrayHandle::ExecutionTypes<Device>::Portal Portal;
PortalConst InputPortal;
Portal OutputPortal;
public:
VTKM_CONT
GatherFloat32(const FloatArrayHandle& inputPortal,
FloatArrayHandle& outputPortal,
const vtkm::Id& size)
: InputPortal(inputPortal.PrepareForInput(Device()))
{
this->OutputPortal = outputPortal.PrepareForOutput(size, Device());
}
typedef void ControlSignature(FieldIn<>);
typedef void ExecutionSignature(WorkIndex, _1);
VTKM_EXEC
void operator()(const vtkm::Id& outIndex, const vtkm::Id& inIndex) const
{
OutputPortal.Set(outIndex, InputPortal.Get(inIndex));
}
}; //class GatherFloat
template <typename Device>
class LinearBVHBuilder::GatherVecCast : public vtkm::worklet::WorkletMapField
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> Vec4IdArrayHandle;
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Int32, 4>> Vec4IntArrayHandle;
typedef typename Vec4IdArrayHandle::ExecutionTypes<Device>::PortalConst PortalConst;
typedef typename Vec4IntArrayHandle::ExecutionTypes<Device>::Portal Portal;
private:
PortalConst InputPortal;
Portal OutputPortal;
public:
VTKM_CONT
GatherVecCast(const Vec4IdArrayHandle& inputPortal,
Vec4IntArrayHandle& outputPortal,
const vtkm::Id& size)
: InputPortal(inputPortal.PrepareForInput(Device()))
{
this->OutputPortal = outputPortal.PrepareForOutput(size, Device());
}
typedef void ControlSignature(FieldIn<>);
typedef void ExecutionSignature(WorkIndex, _1);
VTKM_EXEC
void operator()(const vtkm::Id& outIndex, const vtkm::Id& inIndex) const
{
OutputPortal.Set(outIndex, InputPortal.Get(inIndex));
}
}; //class GatherVec3Id
class LinearBVHBuilder::BVHData
{
public:
//TODO: make private
vtkm::cont::ArrayHandle<vtkm::Float32>* xmins;
vtkm::cont::ArrayHandle<vtkm::Float32>* ymins;
vtkm::cont::ArrayHandle<vtkm::Float32>* zmins;
vtkm::cont::ArrayHandle<vtkm::Float32>* xmaxs;
vtkm::cont::ArrayHandle<vtkm::Float32>* ymaxs;
vtkm::cont::ArrayHandle<vtkm::Float32>* zmaxs;
vtkm::cont::ArrayHandle<vtkm::UInt32> mortonCodes;
vtkm::cont::ArrayHandle<vtkm::Id> parent;
vtkm::cont::ArrayHandle<vtkm::Id> leftChild;
vtkm::cont::ArrayHandle<vtkm::Id> rightChild;
template <typename Device>
VTKM_CONT BVHData(vtkm::Id numPrimitives, Device vtkmNotUsed(device))
: NumPrimitives(numPrimitives)
{
InnerNodeCount = NumPrimitives - 1;
vtkm::Id size = NumPrimitives + InnerNodeCount;
xmins = new vtkm::cont::ArrayHandle<vtkm::Float32>();
ymins = new vtkm::cont::ArrayHandle<vtkm::Float32>();
zmins = new vtkm::cont::ArrayHandle<vtkm::Float32>();
xmaxs = new vtkm::cont::ArrayHandle<vtkm::Float32>();
ymaxs = new vtkm::cont::ArrayHandle<vtkm::Float32>();
zmaxs = new vtkm::cont::ArrayHandle<vtkm::Float32>();
parent.PrepareForOutput(size, Device());
leftChild.PrepareForOutput(InnerNodeCount, Device());
rightChild.PrepareForOutput(InnerNodeCount, Device());
mortonCodes.PrepareForOutput(NumPrimitives, Device());
}
VTKM_CONT
~BVHData()
{
//
delete xmins;
delete ymins;
delete zmins;
delete xmaxs;
delete ymaxs;
delete zmaxs;
}
VTKM_CONT
vtkm::Id GetNumberOfPrimitives() const { return NumPrimitives; }
VTKM_CONT
vtkm::Id GetNumberOfInnerNodes() const { return InnerNodeCount; }
private:
vtkm::Id NumPrimitives;
vtkm::Id InnerNodeCount;
}; // class BVH
template <typename Device>
class LinearBVHBuilder::PropagateAABBs : public vtkm::worklet::WorkletMapField
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Id> IdArrayHandle;
typedef typename vtkm::cont::ArrayHandle<vtkm::Int8> Int8Handle;
typedef typename vtkm::cont::ArrayHandle<Vec<vtkm::Float32, 2>> Float2ArrayHandle;
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Int32, 2>> VecInt2Handle;
typedef typename vtkm::cont::ArrayHandle<Vec<vtkm::Float32, 4>> Float4ArrayHandle;
typedef typename IdArrayHandle::ExecutionTypes<Device>::PortalConst IdConstPortal;
typedef typename Float2ArrayHandle::ExecutionTypes<Device>::Portal Float2ArrayPortal;
typedef typename VecInt2Handle::ExecutionTypes<Device>::Portal Int2ArrayPortal;
typedef typename Int8Handle::ExecutionTypes<Device>::Portal Int8ArrayPortal;
typedef typename Float4ArrayHandle::ExecutionTypes<Device>::Portal Float4ArrayPortal;
Float4ArrayPortal FlatBVH;
IdConstPortal Parents;
IdConstPortal LeftChildren;
IdConstPortal RightChildren;
vtkm::Int32 LeafCount;
//Int8Handle Counters;
//Int8ArrayPortal CountersPortal;
vtkm::exec::AtomicArray<vtkm::Int32, Device> Counters;
public:
VTKM_CONT
PropagateAABBs(IdArrayHandle& parents,
IdArrayHandle& leftChildren,
IdArrayHandle& rightChildren,
vtkm::Int32 leafCount,
Float4ArrayHandle flatBVH,
const vtkm::exec::AtomicArray<vtkm::Int32, Device>& counters)
: Parents(parents.PrepareForInput(Device()))
, LeftChildren(leftChildren.PrepareForInput(Device()))
, RightChildren(rightChildren.PrepareForInput(Device()))
, LeafCount(leafCount)
, Counters(counters)
{
this->FlatBVH = flatBVH.PrepareForOutput((LeafCount - 1) * 4, Device());
}
typedef void ControlSignature(ExecObject,
ExecObject,
ExecObject,
ExecObject,
ExecObject,
ExecObject);
typedef void ExecutionSignature(WorkIndex, _1, _2, _3, _4, _5, _6);
template <typename StrorageType>
VTKM_EXEC_CONT void operator()(
const vtkm::Id workIndex,
const vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32, StrorageType>& xmin,
const vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32, StrorageType>& ymin,
const vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32, StrorageType>& zmin,
const vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32, StrorageType>& xmax,
const vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32, StrorageType>& ymax,
const vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32, StrorageType>& zmax) const
{
//move up into the inner nodes
vtkm::Id currentNode = LeafCount - 1 + workIndex;
vtkm::Vec<vtkm::Id, 2> childVector;
while (currentNode != 0)
{
currentNode = Parents.Get(currentNode);
vtkm::Int32 oldCount = Counters.Add(currentNode, 1);
if (oldCount == 0)
return;
vtkm::Id currentNodeOffset = currentNode * 4;
childVector[0] = LeftChildren.Get(currentNode);
childVector[1] = RightChildren.Get(currentNode);
if (childVector[0] > (LeafCount - 2))
{
childVector[0] = childVector[0] - LeafCount + 1;
vtkm::Vec<vtkm::Float32, 4>
first4Vec; // = FlatBVH.Get(currentNode); only this one needs effects this
first4Vec[0] = xmin.Get(childVector[0]);
first4Vec[1] = ymin.Get(childVector[0]);
first4Vec[2] = zmin.Get(childVector[0]);
first4Vec[3] = xmax.Get(childVector[0]);
FlatBVH.Set(currentNodeOffset, first4Vec);
vtkm::Vec<vtkm::Float32, 4> second4Vec = FlatBVH.Get(currentNodeOffset + 1);
second4Vec[0] = ymax.Get(childVector[0]);
second4Vec[1] = zmax.Get(childVector[0]);
FlatBVH.Set(currentNodeOffset + 1, second4Vec);
childVector[0] = -(childVector[0] + 1);
}
else
{
vtkm::Id child = childVector[0] * 4;
vtkm::Vec<vtkm::Float32, 4> cFirst4Vec = FlatBVH.Get(child);
vtkm::Vec<vtkm::Float32, 4> cSecond4Vec = FlatBVH.Get(child + 1);
vtkm::Vec<vtkm::Float32, 4> cThird4Vec = FlatBVH.Get(child + 2);
cFirst4Vec[0] = vtkm::Min(cFirst4Vec[0], cSecond4Vec[2]);
cFirst4Vec[1] = vtkm::Min(cFirst4Vec[1], cSecond4Vec[3]);
cFirst4Vec[2] = vtkm::Min(cFirst4Vec[2], cThird4Vec[0]);
cFirst4Vec[3] = vtkm::Max(cFirst4Vec[3], cThird4Vec[1]);
FlatBVH.Set(currentNodeOffset, cFirst4Vec);
vtkm::Vec<vtkm::Float32, 4> second4Vec = FlatBVH.Get(currentNodeOffset + 1);
second4Vec[0] = vtkm::Max(cSecond4Vec[0], cThird4Vec[2]);
second4Vec[1] = vtkm::Max(cSecond4Vec[1], cThird4Vec[3]);
FlatBVH.Set(currentNodeOffset + 1, second4Vec);
}
if (childVector[1] > (LeafCount - 2))
{
childVector[1] = childVector[1] - LeafCount + 1;
vtkm::Vec<vtkm::Float32, 4> second4Vec = FlatBVH.Get(currentNodeOffset + 1);
second4Vec[2] = xmin.Get(childVector[1]);
second4Vec[3] = ymin.Get(childVector[1]);
FlatBVH.Set(currentNodeOffset + 1, second4Vec);
vtkm::Vec<vtkm::Float32, 4> third4Vec;
third4Vec[0] = zmin.Get(childVector[1]);
third4Vec[1] = xmax.Get(childVector[1]);
third4Vec[2] = ymax.Get(childVector[1]);
third4Vec[3] = zmax.Get(childVector[1]);
FlatBVH.Set(currentNodeOffset + 2, third4Vec);
childVector[1] = -(childVector[1] + 1);
}
else
{
vtkm::Id child = childVector[1] * 4;
vtkm::Vec<vtkm::Float32, 4> cFirst4Vec = FlatBVH.Get(child);
vtkm::Vec<vtkm::Float32, 4> cSecond4Vec = FlatBVH.Get(child + 1);
vtkm::Vec<vtkm::Float32, 4> cThird4Vec = FlatBVH.Get(child + 2);
vtkm::Vec<vtkm::Float32, 4> second4Vec = FlatBVH.Get(currentNodeOffset + 1);
second4Vec[2] = vtkm::Min(cFirst4Vec[0], cSecond4Vec[2]);
second4Vec[3] = vtkm::Min(cFirst4Vec[1], cSecond4Vec[3]);
FlatBVH.Set(currentNodeOffset + 1, second4Vec);
cThird4Vec[0] = vtkm::Min(cFirst4Vec[2], cThird4Vec[0]);
cThird4Vec[1] = vtkm::Max(cFirst4Vec[3], cThird4Vec[1]);
cThird4Vec[2] = vtkm::Max(cSecond4Vec[0], cThird4Vec[2]);
cThird4Vec[3] = vtkm::Max(cSecond4Vec[1], cThird4Vec[3]);
FlatBVH.Set(currentNodeOffset + 2, cThird4Vec);
}
vtkm::Vec<vtkm::Float32, 4> fourth4Vec;
vtkm::Int32 leftChild =
static_cast<vtkm::Int32>((childVector[0] >= 0) ? childVector[0] * 4 : childVector[0]);
memcpy(&fourth4Vec[0], &leftChild, 4);
vtkm::Int32 rightChild =
static_cast<vtkm::Int32>((childVector[1] >= 0) ? childVector[1] * 4 : childVector[1]);
memcpy(&fourth4Vec[1], &rightChild, 4);
FlatBVH.Set(currentNodeOffset + 3, fourth4Vec);
}
}
}; //class PropagateAABBs
template <typename Device>
class LinearBVHBuilder::TreeBuilder : public vtkm::worklet::WorkletMapField
{
public:
typedef typename vtkm::cont::ArrayHandle<vtkm::UInt32> UIntArrayHandle;
typedef typename vtkm::cont::ArrayHandle<vtkm::Id> IdArrayHandle;
typedef typename UIntArrayHandle::ExecutionTypes<Device>::PortalConst UIntPortalType;
typedef typename IdArrayHandle::ExecutionTypes<Device>::Portal IdPortalType;
private:
UIntPortalType MortonCodePortal;
IdPortalType ParentPortal;
vtkm::Id LeafCount;
vtkm::Id InnerCount;
//TODO: get instrinsic support
VTKM_EXEC
inline vtkm::Int32 CountLeadingZeros(vtkm::UInt32& x) const
{
vtkm::UInt32 y;
vtkm::UInt32 n = 32;
y = x >> 16;
if (y != 0)
{
n = n - 16;
x = y;
}
y = x >> 8;
if (y != 0)
{
n = n - 8;
x = y;
}
y = x >> 4;
if (y != 0)
{
n = n - 4;
x = y;
}
y = x >> 2;
if (y != 0)
{
n = n - 2;
x = y;
}
y = x >> 1;
if (y != 0)
return vtkm::Int32(n - 2);
return vtkm::Int32(n - x);
}
// returns the count of largest shared prefix between
// two morton codes. Ties are broken by the indexes
// a and b.
//
// returns count of the largest binary prefix
VTKM_EXEC
inline vtkm::Int32 delta(const vtkm::Int32& a, const vtkm::Int32& b) const
{
bool tie = false;
bool outOfRange = (b < 0 || b > LeafCount - 1);
//still make the call but with a valid adderss
vtkm::Int32 bb = (outOfRange) ? 0 : b;
vtkm::UInt32 aCode = MortonCodePortal.Get(a);
vtkm::UInt32 bCode = MortonCodePortal.Get(bb);
//use xor to find where they differ
vtkm::UInt32 exOr = aCode ^ bCode;
tie = (exOr == 0);
//break the tie, a and b must always differ
exOr = tie ? vtkm::UInt32(a) ^ vtkm::UInt32(bb) : exOr;
vtkm::Int32 count = CountLeadingZeros(exOr);
if (tie)
count += 32;
count = (outOfRange) ? -1 : count;
return count;
}
public:
VTKM_CONT
TreeBuilder(const UIntArrayHandle& mortonCodesHandle,
IdArrayHandle& parentHandle,
const vtkm::Id& leafCount)
: MortonCodePortal(mortonCodesHandle.PrepareForInput(Device()))
, LeafCount(leafCount)
{
InnerCount = LeafCount - 1;
this->ParentPortal = parentHandle.PrepareForOutput(InnerCount + LeafCount, Device());
}
typedef void ControlSignature(FieldOut<>, FieldOut<>);
typedef void ExecutionSignature(WorkIndex, _1, _2);
VTKM_EXEC
void operator()(const vtkm::Id& index, vtkm::Id& leftChild, vtkm::Id& rightChild) const
{
vtkm::Int32 idx = vtkm::Int32(index);
//something = MortonCodePortal.Get(index) + 1;
//determine range direction
vtkm::Int32 d = 0 > (delta(idx, idx + 1) - delta(idx, idx - 1)) ? -1 : 1;
//find upper bound for the length of the range
vtkm::Int32 minDelta = delta(idx, idx - d);
vtkm::Int32 lMax = 2;
while (delta(idx, idx + lMax * d) > minDelta)
lMax *= 2;
//binary search to find the lower bound
vtkm::Int32 l = 0;
for (int t = lMax / 2; t >= 1; t /= 2)
{
if (delta(idx, idx + (l + t) * d) > minDelta)
l += t;
}
vtkm::Int32 j = idx + l * d;
vtkm::Int32 deltaNode = delta(idx, j);
vtkm::Int32 s = 0;
vtkm::Float32 divFactor = 2.f;
//find the split postition using a binary search
for (vtkm::Int32 t = (vtkm::Int32)ceil(vtkm::Float32(l) / divFactor);;
divFactor *= 2, t = (vtkm::Int32)ceil(vtkm::Float32(l) / divFactor))
{
if (delta(idx, idx + (s + t) * d) > deltaNode)
{
s += t;
}
if (t == 1)
break;
}
vtkm::Int32 split = idx + s * d + vtkm::Min(d, 0);
//assign parent/child pointers
if (vtkm::Min(idx, j) == split)
{
//leaf
ParentPortal.Set(split + InnerCount, idx);
leftChild = split + InnerCount;
}
else
{
//inner node
ParentPortal.Set(split, idx);
leftChild = split;
}
if (vtkm::Max(idx, j) == split + 1)
{
//leaf
ParentPortal.Set(split + InnerCount + 1, idx);
rightChild = split + InnerCount + 1;
}
else
{
ParentPortal.Set(split + 1, idx);
rightChild = split + 1;
}
}
}; // class TreeBuilder
template <typename Device>
VTKM_CONT void LinearBVHBuilder::SortAABBS(
BVHData& bvh,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>>& triangleIndices,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Int32, 4>>& outputTriangleIndices,
Device vtkmNotUsed(device))
{
//create array of indexes to be sorted with morton codes
vtkm::cont::ArrayHandle<vtkm::Id> iterator;
iterator.PrepareForOutput(bvh.GetNumberOfPrimitives(), Device());
vtkm::worklet::DispatcherMapField<CountingIterator, Device> iteratorDispatcher;
iteratorDispatcher.Invoke(iterator);
//std::cout<<"\n\n\n";
//sort the morton codes
vtkm::cont::DeviceAdapterAlgorithm<Device>::SortByKey(bvh.mortonCodes, iterator);
vtkm::Id arraySize = bvh.GetNumberOfPrimitives();
vtkm::cont::ArrayHandle<vtkm::Float32>* tempStorage;
vtkm::cont::ArrayHandle<vtkm::Float32>* tempPtr;
tempStorage = new vtkm::cont::ArrayHandle<vtkm::Float32>();
//xmins
vtkm::worklet::DispatcherMapField<GatherFloat32<Device>, Device>(
GatherFloat32<Device>(*bvh.xmins, *tempStorage, arraySize))
.Invoke(iterator);
tempPtr = bvh.xmins;
bvh.xmins = tempStorage;
tempStorage = tempPtr;
vtkm::worklet::DispatcherMapField<GatherFloat32<Device>, Device>(
GatherFloat32<Device>(*bvh.ymins, *tempStorage, arraySize))
.Invoke(iterator);
tempPtr = bvh.ymins;
bvh.ymins = tempStorage;
tempStorage = tempPtr;
//zmins
vtkm::worklet::DispatcherMapField<GatherFloat32<Device>, Device>(
GatherFloat32<Device>(*bvh.zmins, *tempStorage, arraySize))
.Invoke(iterator);
tempPtr = bvh.zmins;
bvh.zmins = tempStorage;
tempStorage = tempPtr;
//xmaxs
vtkm::worklet::DispatcherMapField<GatherFloat32<Device>, Device>(
GatherFloat32<Device>(*bvh.xmaxs, *tempStorage, arraySize))
.Invoke(iterator);
tempPtr = bvh.xmaxs;
bvh.xmaxs = tempStorage;
tempStorage = tempPtr;
//ymaxs
vtkm::worklet::DispatcherMapField<GatherFloat32<Device>, Device>(
GatherFloat32<Device>(*bvh.ymaxs, *tempStorage, arraySize))
.Invoke(iterator);
tempPtr = bvh.ymaxs;
bvh.ymaxs = tempStorage;
tempStorage = tempPtr;
//zmaxs
vtkm::worklet::DispatcherMapField<GatherFloat32<Device>, Device>(
GatherFloat32<Device>(*bvh.zmaxs, *tempStorage, arraySize))
.Invoke(iterator);
tempPtr = bvh.zmaxs;
bvh.zmaxs = tempStorage;
tempStorage = tempPtr;
vtkm::worklet::DispatcherMapField<GatherVecCast<Device>, Device>(
GatherVecCast<Device>(triangleIndices, outputTriangleIndices, arraySize))
.Invoke(iterator);
delete tempStorage;
} // method SortAABBs
// Adding this as a template parameter to allow restricted types and
// storage for dynamic coordinate system to limit crazy code bloat and
// compile times.
//
template <typename Device>
VTKM_CONT void LinearBVHBuilder::RunOnDevice(LinearBVH& linearBVH, Device device)
{
Logger* logger = Logger::GetInstance();
logger->OpenLogEntry("bvh_constuct");
logger->AddLogData("device", GetDeviceString(Device()));
vtkm::cont::Timer<Device> constructTimer;
vtkm::cont::DynamicArrayHandleCoordinateSystem coordsHandle = linearBVH.GetCoordsHandle();
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> triangleIndices = linearBVH.GetTriangles();
vtkm::Id numberOfTriangles = linearBVH.GetNumberOfTriangles();
logger->AddLogData("bvh_num_triangles ", numberOfTriangles);
const vtkm::Id numBBoxes = numberOfTriangles;
BVHData bvh(numBBoxes, device);
vtkm::cont::Timer<Device> timer;
vtkm::worklet::DispatcherMapField<FindAABBs, Device>(FindAABBs())
.Invoke(triangleIndices,
*bvh.xmins,
*bvh.ymins,
*bvh.zmins,
*bvh.xmaxs,
*bvh.ymaxs,
*bvh.zmaxs,
coordsHandle);
vtkm::Float64 time = timer.GetElapsedTime();
logger->AddLogData("find_aabb", time);
timer.Reset();
// Find the extent of all bounding boxes to generate normalization for morton codes
vtkm::Vec<vtkm::Float32, 3> minExtent(vtkm::Infinity32(), vtkm::Infinity32(), vtkm::Infinity32());
vtkm::Vec<vtkm::Float32, 3> maxExtent(
vtkm::NegativeInfinity32(), vtkm::NegativeInfinity32(), vtkm::NegativeInfinity32());
maxExtent[0] =
vtkm::cont::DeviceAdapterAlgorithm<Device>::Reduce(*bvh.xmaxs, maxExtent[0], MaxValue());
maxExtent[1] =
vtkm::cont::DeviceAdapterAlgorithm<Device>::Reduce(*bvh.ymaxs, maxExtent[1], MaxValue());
maxExtent[2] =
vtkm::cont::DeviceAdapterAlgorithm<Device>::Reduce(*bvh.zmaxs, maxExtent[2], MaxValue());
minExtent[0] =
vtkm::cont::DeviceAdapterAlgorithm<Device>::Reduce(*bvh.xmins, minExtent[0], MinValue());
minExtent[1] =
vtkm::cont::DeviceAdapterAlgorithm<Device>::Reduce(*bvh.ymins, minExtent[1], MinValue());
minExtent[2] =
vtkm::cont::DeviceAdapterAlgorithm<Device>::Reduce(*bvh.zmins, minExtent[2], MinValue());
time = timer.GetElapsedTime();
logger->AddLogData("calc_extents", time);
timer.Reset();
vtkm::Vec<vtkm::Float32, 3> deltaExtent = maxExtent - minExtent;
vtkm::Vec<vtkm::Float32, 3> inverseExtent;
for (int i = 0; i < 3; ++i)
{
inverseExtent[i] = (deltaExtent[i] == 0.f) ? 0 : 1.f / deltaExtent[i];
}
//Generate the morton codes
vtkm::worklet::DispatcherMapField<MortonCodeAABB, Device>(
MortonCodeAABB(inverseExtent, minExtent))
.Invoke(
*bvh.xmins, *bvh.ymins, *bvh.zmins, *bvh.xmaxs, *bvh.ymaxs, *bvh.zmaxs, bvh.mortonCodes);
time = timer.GetElapsedTime();
logger->AddLogData("morton_codes", time);
timer.Reset();
linearBVH.Allocate(bvh.GetNumberOfPrimitives(), Device());
SortAABBS(bvh, triangleIndices, linearBVH.LeafNodes, Device());
time = timer.GetElapsedTime();
logger->AddLogData("sort_aabbs", time);
timer.Reset();
vtkm::worklet::DispatcherMapField<TreeBuilder<Device>, Device>(
TreeBuilder<Device>(bvh.mortonCodes, bvh.parent, bvh.GetNumberOfPrimitives()))
.Invoke(bvh.leftChild, bvh.rightChild);
time = timer.GetElapsedTime();
logger->AddLogData("build_tree", time);
timer.Reset();
const vtkm::Int32 primitiveCount = vtkm::Int32(bvh.GetNumberOfPrimitives());
vtkm::cont::ArrayHandle<vtkm::Int32> counters;
counters.PrepareForOutput(bvh.GetNumberOfPrimitives() - 1, Device());
vtkm::Int32 zero = 0;
vtkm::worklet::DispatcherMapField<MemSet<vtkm::Int32>, Device>(MemSet<vtkm::Int32>(zero))
.Invoke(counters);
vtkm::exec::AtomicArray<vtkm::Int32, Device> atomicCounters(counters);
vtkm::worklet::DispatcherMapField<PropagateAABBs<Device>, Device>(
PropagateAABBs<Device>(
bvh.parent, bvh.leftChild, bvh.rightChild, primitiveCount, linearBVH.FlatBVH, atomicCounters))
.Invoke(vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32>(*bvh.xmins),
vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32>(*bvh.ymins),
vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32>(*bvh.zmins),
vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32>(*bvh.xmaxs),
vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32>(*bvh.ymaxs),
vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32>(*bvh.zmaxs));
time = timer.GetElapsedTime();
logger->AddLogData("propagate_aabbs", time);
time = constructTimer.GetElapsedTime();
logger->CloseLogEntry(time);
}
} //namespace detail
struct LinearBVH::ConstructFunctor
{
LinearBVH* Self;
VTKM_CONT
ConstructFunctor(LinearBVH* self)
: Self(self)
{
}
template <typename Device>
bool operator()(Device)
{
Self->ConstructOnDevice(Device());
return true;
}
};
LinearBVH::LinearBVH()
: IsConstructed(false)
, CanConstruct(false){};
VTKM_CONT
LinearBVH::LinearBVH(vtkm::cont::DynamicArrayHandleCoordinateSystem coordsHandle,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> triangles)
: CoordsHandle(coordsHandle)
, Triangles(triangles)
, IsConstructed(false)
, CanConstruct(true)
{
}
VTKM_CONT
LinearBVH::LinearBVH(const LinearBVH& other)
: FlatBVH(other.FlatBVH)
, LeafNodes(other.LeafNodes)
, ExtentMin(other.ExtentMin)
, ExtentMax(other.ExtentMax)
, LeafCount(other.LeafCount)
, CoordsHandle(other.CoordsHandle)
, Triangles(other.Triangles)
, IsConstructed(other.IsConstructed)
, CanConstruct(other.CanConstruct)
{
}
template <typename Device>
VTKM_CONT void LinearBVH::Allocate(const vtkm::Id& leafCount, Device deviceAdapter)
{
LeafCount = leafCount;
LeafNodes.PrepareForOutput(leafCount, deviceAdapter);
FlatBVH.PrepareForOutput((leafCount - 1) * 4, deviceAdapter);
}
void LinearBVH::Construct()
{
if (IsConstructed)
return;
if (!CanConstruct)
throw vtkm::cont::ErrorBadValue(
"Linear BVH: coordinates and triangles must be set before calling construct!");
ConstructFunctor functor(this);
vtkm::cont::TryExecute(functor);
IsConstructed = true;
}
VTKM_CONT
void LinearBVH::SetData(vtkm::cont::DynamicArrayHandleCoordinateSystem coordsHandle,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> triangles)
{
CoordsHandle = coordsHandle;
Triangles = triangles;
IsConstructed = false;
CanConstruct = true;
}
template <typename Device>
void LinearBVH::ConstructOnDevice(Device device)
{
Logger* logger = Logger::GetInstance();
vtkm::cont::Timer<Device> timer;
logger->OpenLogEntry("bvh");
if (!CanConstruct)
throw vtkm::cont::ErrorBadValue(
"Linear BVH: coordinates and triangles must be set before calling construct!");
if (!IsConstructed)
{
detail::LinearBVHBuilder builder;
builder.RunOnDevice(*this, device);
IsConstructed = true;
}
vtkm::Float64 time = timer.GetElapsedTime();
logger->CloseLogEntry(time);
}
VTKM_CONT
bool LinearBVH::GetIsConstructed() const
{
return IsConstructed;
}
VTKM_CONT
vtkm::cont::DynamicArrayHandleCoordinateSystem LinearBVH::GetCoordsHandle() const
{
return CoordsHandle;
}
VTKM_CONT
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> LinearBVH::GetTriangles() const
{
return Triangles;
}
vtkm::Id LinearBVH::GetNumberOfTriangles() const
{
return Triangles.GetPortalConstControl().GetNumberOfValues();
}
}
}
} // namespace vtkm::rendering::raytracing

@ -19,25 +19,10 @@
//============================================================================
#ifndef vtk_m_worklet_BoundingVolumeHierachy_h
#define vtk_m_worklet_BoundingVolumeHierachy_h
#include <math.h>
#include <vtkm/Math.h>
#include <vtkm/VectorAnalysis.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DeviceAdapter.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/exec/AtomicArray.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/raytracing/RayTracingTypeDefs.h>
#include <vtkm/rendering/raytracing/Worklets.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <cstring>
#include <limits>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/rendering/vtkm_rendering_export.h>
namespace vtkm
{
@ -45,787 +30,62 @@ namespace rendering
{
namespace raytracing
{
//
// This is the data structure that is passed to the ray tracer.
//
//template<typename DeviceAdapter>
class LinearBVH
class VTKM_RENDERING_EXPORT LinearBVH
{
public:
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>> FlatBVH;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Int32, 4>> LeafNodes;
typedef vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>> InnerNodesHandle;
typedef vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Int32, 4>> LeafNodesHandle;
InnerNodesHandle FlatBVH;
LeafNodesHandle LeafNodes;
vtkm::Vec<Float32, 3> ExtentMin;
vtkm::Vec<Float32, 3> ExtentMax;
struct ConstructFunctor;
vtkm::Id LeafCount;
protected:
vtkm::cont::DynamicArrayHandleCoordinateSystem CoordsHandle;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> Triangles;
bool IsConstructed;
bool CanConstruct;
public:
LinearBVH();
VTKM_CONT
LinearBVH() {}
LinearBVH(vtkm::cont::DynamicArrayHandleCoordinateSystem coordsHandle,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> triangles);
VTKM_CONT
LinearBVH(const LinearBVH& other);
template <typename DeviceAdapter>
VTKM_CONT void Allocate(const vtkm::Id& leafCount, DeviceAdapter deviceAdapter)
{
LeafCount = leafCount;
LeafNodes.PrepareForOutput(leafCount, deviceAdapter);
FlatBVH.PrepareForOutput((leafCount - 1) * 4, deviceAdapter);
}
VTKM_CONT void Allocate(const vtkm::Id& leafCount, DeviceAdapter deviceAdapter);
VTKM_CONT
void Construct();
VTKM_CONT
void SetData(vtkm::cont::DynamicArrayHandleCoordinateSystem coordsHandle,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> triangles);
template <typename Device>
VTKM_CONT void ConstructOnDevice(Device device);
VTKM_CONT
bool GetIsConstructed() const;
VTKM_CONT
vtkm::cont::DynamicArrayHandleCoordinateSystem GetCoordsHandle() const;
VTKM_CONT
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> GetTriangles() const;
vtkm::Id GetNumberOfTriangles() const;
}; // class LinearBVH
template <typename DeviceAdapter>
class LinearBVHBuilder
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float64, 3>> Vec3DoubleArrayHandle;
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 3>> Vec3FloatArrayHandle;
typedef
typename Vec3DoubleArrayHandle::ExecutionTypes<DeviceAdapter>::PortalConst Point64PortalConst;
typedef
typename Vec3FloatArrayHandle::ExecutionTypes<DeviceAdapter>::PortalConst Point32PortalConst;
public:
class CountingIterator : public vtkm::worklet::WorkletMapField
{
public:
VTKM_CONT
CountingIterator() {}
typedef void ControlSignature(FieldOut<>);
typedef void ExecutionSignature(WorkIndex, _1);
VTKM_EXEC
void operator()(const vtkm::Id& index, vtkm::Id& outId) const { outId = index; }
}; //class countingIterator
class FindAABBs : public vtkm::worklet::WorkletMapField
{
public:
VTKM_CONT
FindAABBs() {}
typedef void ControlSignature(FieldIn<>,
FieldOut<>,
FieldOut<>,
FieldOut<>,
FieldOut<>,
FieldOut<>,
FieldOut<>,
WholeArrayIn<Vec3RenderingTypes>);
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6, _7, _8);
template <typename PointPortalType>
VTKM_EXEC void operator()(const vtkm::Vec<vtkm::Id, 4> indices,
vtkm::Float32& xmin,
vtkm::Float32& ymin,
vtkm::Float32& zmin,
vtkm::Float32& xmax,
vtkm::Float32& ymax,
vtkm::Float32& zmax,
const PointPortalType& points) const
{
// cast to Float32
vtkm::Vec<vtkm::Float32, 3> point;
point = static_cast<vtkm::Vec<vtkm::Float32, 3>>(points.Get(indices[1]));
xmin = point[0];
ymin = point[1];
zmin = point[2];
xmax = xmin;
ymax = ymin;
zmax = zmin;
point = static_cast<vtkm::Vec<vtkm::Float32, 3>>(points.Get(indices[2]));
xmin = vtkm::Min(xmin, point[0]);
ymin = vtkm::Min(ymin, point[1]);
zmin = vtkm::Min(zmin, point[2]);
xmax = vtkm::Max(xmax, point[0]);
ymax = vtkm::Max(ymax, point[1]);
zmax = vtkm::Max(zmax, point[2]);
point = static_cast<vtkm::Vec<vtkm::Float32, 3>>(points.Get(indices[3]));
xmin = vtkm::Min(xmin, point[0]);
ymin = vtkm::Min(ymin, point[1]);
zmin = vtkm::Min(zmin, point[2]);
xmax = vtkm::Max(xmax, point[0]);
ymax = vtkm::Max(ymax, point[1]);
zmax = vtkm::Max(zmax, point[2]);
}
}; //class FindAABBs
class GatherFloat32 : public vtkm::worklet::WorkletMapField
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Float32> FloatArrayHandle;
typedef typename FloatArrayHandle::ExecutionTypes<DeviceAdapter>::PortalConst PortalConst;
typedef typename FloatArrayHandle::ExecutionTypes<DeviceAdapter>::Portal Portal;
private:
PortalConst InputPortal;
Portal OutputPortal;
public:
VTKM_CONT
GatherFloat32(const FloatArrayHandle& inputPortal,
FloatArrayHandle& outputPortal,
const vtkm::Id& size)
: InputPortal(inputPortal.PrepareForInput(DeviceAdapter()))
{
this->OutputPortal = outputPortal.PrepareForOutput(size, DeviceAdapter());
}
typedef void ControlSignature(FieldIn<>);
typedef void ExecutionSignature(WorkIndex, _1);
VTKM_EXEC
void operator()(const vtkm::Id& outIndex, const vtkm::Id& inIndex) const
{
OutputPortal.Set(outIndex, InputPortal.Get(inIndex));
}
}; //class GatherFloat
class GatherVecCast : public vtkm::worklet::WorkletMapField
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> Vec4IdArrayHandle;
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Int32, 4>> Vec4IntArrayHandle;
typedef typename Vec4IdArrayHandle::ExecutionTypes<DeviceAdapter>::PortalConst PortalConst;
typedef typename Vec4IntArrayHandle::ExecutionTypes<DeviceAdapter>::Portal Portal;
private:
PortalConst InputPortal;
Portal OutputPortal;
public:
VTKM_CONT
GatherVecCast(const Vec4IdArrayHandle& inputPortal,
Vec4IntArrayHandle& outputPortal,
const vtkm::Id& size)
: InputPortal(inputPortal.PrepareForInput(DeviceAdapter()))
{
this->OutputPortal = outputPortal.PrepareForOutput(size, DeviceAdapter());
}
typedef void ControlSignature(FieldIn<>);
typedef void ExecutionSignature(WorkIndex, _1);
VTKM_EXEC
void operator()(const vtkm::Id& outIndex, const vtkm::Id& inIndex) const
{
OutputPortal.Set(outIndex, InputPortal.Get(inIndex));
}
}; //class GatherVec3Id
class BVHData
{
public:
//TODO: make private
vtkm::cont::ArrayHandle<vtkm::Float32>* xmins;
vtkm::cont::ArrayHandle<vtkm::Float32>* ymins;
vtkm::cont::ArrayHandle<vtkm::Float32>* zmins;
vtkm::cont::ArrayHandle<vtkm::Float32>* xmaxs;
vtkm::cont::ArrayHandle<vtkm::Float32>* ymaxs;
vtkm::cont::ArrayHandle<vtkm::Float32>* zmaxs;
vtkm::cont::ArrayHandle<vtkm::UInt32> mortonCodes;
vtkm::cont::ArrayHandle<vtkm::Id> parent;
vtkm::cont::ArrayHandle<vtkm::Id> leftChild;
vtkm::cont::ArrayHandle<vtkm::Id> rightChild;
VTKM_CONT
BVHData(vtkm::Id numPrimitives)
: NumPrimitives(numPrimitives)
{
InnerNodeCount = NumPrimitives - 1;
vtkm::Id size = NumPrimitives + InnerNodeCount;
xmins = new vtkm::cont::ArrayHandle<vtkm::Float32>();
ymins = new vtkm::cont::ArrayHandle<vtkm::Float32>();
zmins = new vtkm::cont::ArrayHandle<vtkm::Float32>();
xmaxs = new vtkm::cont::ArrayHandle<vtkm::Float32>();
ymaxs = new vtkm::cont::ArrayHandle<vtkm::Float32>();
zmaxs = new vtkm::cont::ArrayHandle<vtkm::Float32>();
parent.PrepareForOutput(size, DeviceAdapter());
leftChild.PrepareForOutput(InnerNodeCount, DeviceAdapter());
rightChild.PrepareForOutput(InnerNodeCount, DeviceAdapter());
mortonCodes.PrepareForOutput(NumPrimitives, DeviceAdapter());
}
VTKM_CONT
~BVHData()
{
//
delete xmins;
delete ymins;
delete zmins;
delete xmaxs;
delete ymaxs;
delete zmaxs;
}
VTKM_CONT
vtkm::Id GetNumberOfPrimitives() const { return NumPrimitives; }
VTKM_CONT
vtkm::Id GetNumberOfInnerNodes() const { return InnerNodeCount; }
private:
vtkm::Id NumPrimitives;
vtkm::Id InnerNodeCount;
}; // class BVH
class PropagateAABBs : public vtkm::worklet::WorkletMapField
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Id> IdArrayHandle;
typedef typename vtkm::cont::ArrayHandle<vtkm::Int8> Int8Handle;
typedef typename vtkm::cont::ArrayHandle<Vec<vtkm::Float32, 2>> Float2ArrayHandle;
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Int32, 2>> VecInt2Handle;
typedef typename vtkm::cont::ArrayHandle<Vec<vtkm::Float32, 4>> Float4ArrayHandle;
typedef typename IdArrayHandle::ExecutionTypes<DeviceAdapter>::PortalConst IdConstPortal;
typedef typename Float2ArrayHandle::ExecutionTypes<DeviceAdapter>::Portal Float2ArrayPortal;
typedef typename VecInt2Handle::ExecutionTypes<DeviceAdapter>::Portal Int2ArrayPortal;
typedef typename Int8Handle::ExecutionTypes<DeviceAdapter>::Portal Int8ArrayPortal;
typedef typename Float4ArrayHandle::ExecutionTypes<DeviceAdapter>::Portal Float4ArrayPortal;
Float4ArrayPortal FlatBVH;
IdConstPortal Parents;
IdConstPortal LeftChildren;
IdConstPortal RightChildren;
vtkm::Int32 LeafCount;
//Int8Handle Counters;
//Int8ArrayPortal CountersPortal;
vtkm::exec::AtomicArray<vtkm::Int32, DeviceAdapter> Counters;
public:
VTKM_CONT
PropagateAABBs(IdArrayHandle& parents,
IdArrayHandle& leftChildren,
IdArrayHandle& rightChildren,
vtkm::Int32 leafCount,
Float4ArrayHandle flatBVH,
const vtkm::exec::AtomicArray<vtkm::Int32, DeviceAdapter>& counters)
: Parents(parents.PrepareForInput(DeviceAdapter()))
, LeftChildren(leftChildren.PrepareForInput(DeviceAdapter()))
, RightChildren(rightChildren.PrepareForInput(DeviceAdapter()))
, LeafCount(leafCount)
, Counters(counters)
{
this->FlatBVH = flatBVH.PrepareForOutput((LeafCount - 1) * 4, DeviceAdapter());
}
typedef void ControlSignature(ExecObject,
ExecObject,
ExecObject,
ExecObject,
ExecObject,
ExecObject);
typedef void ExecutionSignature(WorkIndex, _1, _2, _3, _4, _5, _6);
template <typename StrorageType>
VTKM_EXEC_CONT void operator()(
const vtkm::Id workIndex,
const vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32, StrorageType>& xmin,
const vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32, StrorageType>& ymin,
const vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32, StrorageType>& zmin,
const vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32, StrorageType>& xmax,
const vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32, StrorageType>& ymax,
const vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32, StrorageType>& zmax) const
{
//move up into the inner nodes
vtkm::Id currentNode = LeafCount - 1 + workIndex;
vtkm::Vec<vtkm::Id, 2> childVector;
while (currentNode != 0)
{
currentNode = Parents.Get(currentNode);
vtkm::Int32 oldCount = Counters.Add(currentNode, 1);
if (oldCount == 0)
return;
vtkm::Id currentNodeOffset = currentNode * 4;
childVector[0] = LeftChildren.Get(currentNode);
childVector[1] = RightChildren.Get(currentNode);
if (childVector[0] > (LeafCount - 2))
{
childVector[0] = childVector[0] - LeafCount + 1;
vtkm::Vec<vtkm::Float32, 4>
first4Vec; // = FlatBVH.Get(currentNode); only this one needs effects this
first4Vec[0] = xmin.Get(childVector[0]);
first4Vec[1] = ymin.Get(childVector[0]);
first4Vec[2] = zmin.Get(childVector[0]);
first4Vec[3] = xmax.Get(childVector[0]);
FlatBVH.Set(currentNodeOffset, first4Vec);
vtkm::Vec<vtkm::Float32, 4> second4Vec = FlatBVH.Get(currentNodeOffset + 1);
second4Vec[0] = ymax.Get(childVector[0]);
second4Vec[1] = zmax.Get(childVector[0]);
FlatBVH.Set(currentNodeOffset + 1, second4Vec);
childVector[0] = -(childVector[0] + 1);
}
else
{
vtkm::Id child = childVector[0] * 4;
vtkm::Vec<vtkm::Float32, 4> cFirst4Vec = FlatBVH.Get(child);
vtkm::Vec<vtkm::Float32, 4> cSecond4Vec = FlatBVH.Get(child + 1);
vtkm::Vec<vtkm::Float32, 4> cThird4Vec = FlatBVH.Get(child + 2);
cFirst4Vec[0] = vtkm::Min(cFirst4Vec[0], cSecond4Vec[2]);
cFirst4Vec[1] = vtkm::Min(cFirst4Vec[1], cSecond4Vec[3]);
cFirst4Vec[2] = vtkm::Min(cFirst4Vec[2], cThird4Vec[0]);
cFirst4Vec[3] = vtkm::Max(cFirst4Vec[3], cThird4Vec[1]);
FlatBVH.Set(currentNodeOffset, cFirst4Vec);
vtkm::Vec<vtkm::Float32, 4> second4Vec = FlatBVH.Get(currentNodeOffset + 1);
second4Vec[0] = vtkm::Max(cSecond4Vec[0], cThird4Vec[2]);
second4Vec[1] = vtkm::Max(cSecond4Vec[1], cThird4Vec[3]);
FlatBVH.Set(currentNodeOffset + 1, second4Vec);
}
if (childVector[1] > (LeafCount - 2))
{
childVector[1] = childVector[1] - LeafCount + 1;
vtkm::Vec<vtkm::Float32, 4> second4Vec = FlatBVH.Get(currentNodeOffset + 1);
second4Vec[2] = xmin.Get(childVector[1]);
second4Vec[3] = ymin.Get(childVector[1]);
FlatBVH.Set(currentNodeOffset + 1, second4Vec);
vtkm::Vec<vtkm::Float32, 4> third4Vec;
third4Vec[0] = zmin.Get(childVector[1]);
third4Vec[1] = xmax.Get(childVector[1]);
third4Vec[2] = ymax.Get(childVector[1]);
third4Vec[3] = zmax.Get(childVector[1]);
FlatBVH.Set(currentNodeOffset + 2, third4Vec);
childVector[1] = -(childVector[1] + 1);
}
else
{
vtkm::Id child = childVector[1] * 4;
vtkm::Vec<vtkm::Float32, 4> cFirst4Vec = FlatBVH.Get(child);
vtkm::Vec<vtkm::Float32, 4> cSecond4Vec = FlatBVH.Get(child + 1);
vtkm::Vec<vtkm::Float32, 4> cThird4Vec = FlatBVH.Get(child + 2);
vtkm::Vec<vtkm::Float32, 4> second4Vec = FlatBVH.Get(currentNodeOffset + 1);
second4Vec[2] = vtkm::Min(cFirst4Vec[0], cSecond4Vec[2]);
second4Vec[3] = vtkm::Min(cFirst4Vec[1], cSecond4Vec[3]);
FlatBVH.Set(currentNodeOffset + 1, second4Vec);
cThird4Vec[0] = vtkm::Min(cFirst4Vec[2], cThird4Vec[0]);
cThird4Vec[1] = vtkm::Max(cFirst4Vec[3], cThird4Vec[1]);
cThird4Vec[2] = vtkm::Max(cSecond4Vec[0], cThird4Vec[2]);
cThird4Vec[3] = vtkm::Max(cSecond4Vec[1], cThird4Vec[3]);
FlatBVH.Set(currentNodeOffset + 2, cThird4Vec);
}
vtkm::Vec<vtkm::Float32, 4> fourth4Vec;
vtkm::Int32 leftChild =
static_cast<vtkm::Int32>((childVector[0] >= 0) ? childVector[0] * 4 : childVector[0]);
memcpy(&fourth4Vec[0], &leftChild, 4);
vtkm::Int32 rightChild =
static_cast<vtkm::Int32>((childVector[1] >= 0) ? childVector[1] * 4 : childVector[1]);
memcpy(&fourth4Vec[1], &rightChild, 4);
FlatBVH.Set(currentNodeOffset + 3, fourth4Vec);
}
}
}; //class PropagateAABBs
class MortonCodeAABB : public vtkm::worklet::WorkletMapField
{
private:
// (1.f / dx),(1.f / dy), (1.f, / dz)
vtkm::Vec<vtkm::Float32, 3> InverseExtent;
vtkm::Vec<vtkm::Float32, 3> MinCoordinate;
//expands 10-bit unsigned int into 30 bits
VTKM_EXEC
vtkm::UInt32 ExpandBits(vtkm::UInt32 x) const
{
x = (x * 0x00010001u) & 0xFF0000FFu;
x = (x * 0x00000101u) & 0x0F00F00Fu;
x = (x * 0x00000011u) & 0xC30C30C3u;
x = (x * 0x00000005u) & 0x49249249u;
return x;
}
//Returns 30 bit morton code for coordinates for
//coordinates in the unit cude
VTKM_EXEC
vtkm::UInt32 Morton3D(vtkm::Float32& x, vtkm::Float32& y, vtkm::Float32& z) const
{
//take the first 10 bits
x = fminf(fmaxf(x * 1024.0f, 0.0f), 1023.0f);
y = fminf(fmaxf(y * 1024.0f, 0.0f), 1023.0f);
z = fminf(fmaxf(z * 1024.0f, 0.0f), 1023.0f);
//expand the 10 bits to 30
vtkm::UInt32 xx = ExpandBits((vtkm::UInt32)x);
vtkm::UInt32 yy = ExpandBits((vtkm::UInt32)y);
vtkm::UInt32 zz = ExpandBits((vtkm::UInt32)z);
//interleave coordinates
return xx * 4 + yy * 2 + zz;
}
public:
VTKM_CONT
MortonCodeAABB(const vtkm::Vec<vtkm::Float32, 3>& inverseExtent,
const vtkm::Vec<vtkm::Float32, 3>& minCoordinate)
: InverseExtent(inverseExtent)
, MinCoordinate(minCoordinate)
{
}
typedef void ControlSignature(FieldIn<>,
FieldIn<>,
FieldIn<>,
FieldIn<>,
FieldIn<>,
FieldIn<>,
FieldOut<>);
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6, _7);
typedef _7 InputDomain;
VTKM_EXEC
void operator()(const vtkm::Float32& xmin,
const vtkm::Float32& ymin,
const vtkm::Float32& zmin,
const vtkm::Float32& xmax,
const vtkm::Float32& ymax,
const vtkm::Float32& zmax,
vtkm::UInt32& mortonCode) const
{
vtkm::Vec<vtkm::Float32, 3> direction(xmax - xmin, ymax - ymin, zmax - zmin);
vtkm::Float32 halfDistance = sqrtf(vtkm::dot(direction, direction)) * 0.5f;
vtkm::Normalize(direction);
vtkm::Float32 centroidx = xmin + halfDistance * direction[0] - MinCoordinate[0];
vtkm::Float32 centroidy = ymin + halfDistance * direction[1] - MinCoordinate[1];
vtkm::Float32 centroidz = zmin + halfDistance * direction[2] - MinCoordinate[2];
//normalize the centroid tp 10 bits
centroidx *= InverseExtent[0];
centroidy *= InverseExtent[1];
centroidz *= InverseExtent[2];
mortonCode = Morton3D(centroidx, centroidy, centroidz);
}
}; // class MortonCodeAABB
class TreeBuilder : public vtkm::worklet::WorkletMapField
{
public:
typedef typename vtkm::cont::ArrayHandle<vtkm::UInt32> UIntArrayHandle;
typedef typename vtkm::cont::ArrayHandle<vtkm::Id> IdArrayHandle;
typedef typename UIntArrayHandle::ExecutionTypes<DeviceAdapter>::PortalConst UIntPortalType;
typedef typename IdArrayHandle::ExecutionTypes<DeviceAdapter>::Portal IdPortalType;
private:
UIntPortalType MortonCodePortal;
IdPortalType ParentPortal;
vtkm::Id LeafCount;
vtkm::Id InnerCount;
//TODO: get instrinsic support
VTKM_EXEC
vtkm::Int32 CountLeadingZeros(vtkm::UInt32& x) const
{
vtkm::UInt32 y;
vtkm::UInt32 n = 32;
y = x >> 16;
if (y != 0)
{
n = n - 16;
x = y;
}
y = x >> 8;
if (y != 0)
{
n = n - 8;
x = y;
}
y = x >> 4;
if (y != 0)
{
n = n - 4;
x = y;
}
y = x >> 2;
if (y != 0)
{
n = n - 2;
x = y;
}
y = x >> 1;
if (y != 0)
return vtkm::Int32(n - 2);
return vtkm::Int32(n - x);
}
// returns the count of largest shared prefix between
// two morton codes. Ties are broken by the indexes
// a and b.
//
// returns count of the largest binary prefix
VTKM_EXEC
vtkm::Int32 delta(const vtkm::Int32& a, const vtkm::Int32& b) const
{
bool tie = false;
bool outOfRange = (b < 0 || b > LeafCount - 1);
//still make the call but with a valid adderss
vtkm::Int32 bb = (outOfRange) ? 0 : b;
vtkm::UInt32 aCode = MortonCodePortal.Get(a);
vtkm::UInt32 bCode = MortonCodePortal.Get(bb);
//use xor to find where they differ
vtkm::UInt32 exOr = aCode ^ bCode;
tie = (exOr == 0);
//break the tie, a and b must always differ
exOr = tie ? vtkm::UInt32(a) ^ vtkm::UInt32(bb) : exOr;
vtkm::Int32 count = CountLeadingZeros(exOr);
if (tie)
count += 32;
count = (outOfRange) ? -1 : count;
return count;
}
public:
VTKM_CONT
TreeBuilder(const UIntArrayHandle& mortonCodesHandle,
IdArrayHandle& parentHandle,
const vtkm::Id& leafCount)
: MortonCodePortal(mortonCodesHandle.PrepareForInput(DeviceAdapter()))
, LeafCount(leafCount)
{
InnerCount = LeafCount - 1;
this->ParentPortal = parentHandle.PrepareForOutput(InnerCount + LeafCount, DeviceAdapter());
}
typedef void ControlSignature(FieldOut<>, FieldOut<>);
typedef void ExecutionSignature(WorkIndex, _1, _2);
VTKM_EXEC
void operator()(const vtkm::Id& index, vtkm::Id& leftChild, vtkm::Id& rightChild) const
{
vtkm::Int32 idx = vtkm::Int32(index);
//something = MortonCodePortal.Get(index) + 1;
//determine range direction
vtkm::Int32 d = 0 > (delta(idx, idx + 1) - delta(idx, idx - 1)) ? -1 : 1;
//find upper bound for the length of the range
vtkm::Int32 minDelta = delta(idx, idx - d);
vtkm::Int32 lMax = 2;
while (delta(idx, idx + lMax * d) > minDelta)
lMax *= 2;
//binary search to find the lower bound
vtkm::Int32 l = 0;
for (int t = lMax / 2; t >= 1; t /= 2)
{
if (delta(idx, idx + (l + t) * d) > minDelta)
l += t;
}
vtkm::Int32 j = idx + l * d;
vtkm::Int32 deltaNode = delta(idx, j);
vtkm::Int32 s = 0;
vtkm::Float32 divFactor = 2.f;
//find the split postition using a binary search
for (vtkm::Int32 t = (vtkm::Int32)ceil(vtkm::Float32(l) / divFactor);;
divFactor *= 2, t = (vtkm::Int32)ceil(vtkm::Float32(l) / divFactor))
{
if (delta(idx, idx + (s + t) * d) > deltaNode)
{
s += t;
}
if (t == 1)
break;
}
vtkm::Int32 split = idx + s * d + vtkm::Min(d, 0);
//assign parent/child pointers
if (vtkm::Min(idx, j) == split)
{
//leaf
ParentPortal.Set(split + InnerCount, idx);
leftChild = split + InnerCount;
}
else
{
//inner node
ParentPortal.Set(split, idx);
leftChild = split;
}
if (vtkm::Max(idx, j) == split + 1)
{
//leaf
ParentPortal.Set(split + InnerCount + 1, idx);
rightChild = split + InnerCount + 1;
}
else
{
ParentPortal.Set(split + 1, idx);
rightChild = split + 1;
}
}
}; // class TreeBuilder
public:
VTKM_CONT
LinearBVHBuilder() {}
VTKM_CONT
void SortAABBS(BVHData& bvh,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>>& triangleIndices,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Int32, 4>>& outputTriangleIndices)
{
//create array of indexes to be sorted with morton codes
vtkm::cont::ArrayHandle<vtkm::Id> iterator;
iterator.PrepareForOutput(bvh.GetNumberOfPrimitives(), DeviceAdapter());
vtkm::worklet::DispatcherMapField<CountingIterator> iteratorDispatcher;
iteratorDispatcher.Invoke(iterator);
/*
for(int i = 0; i < bvh.GetNumberOfPrimitives(); i++)
{
//std::cout<<iterator.GetPortalControl().Get(i)
<<" "<<bvh.mortonCodes.GetPortalControl().Get(i)
<<" "<<bvh.xmins->GetPortalControl().Get(i)
<<" "<<bvh.ymins->GetPortalControl().Get(i)
<<" "<<bvh.zmins->GetPortalControl().Get(i)
<<" "<<bvh.xmaxs->GetPortalControl().Get(i)
<<" "<<bvh.ymaxs->GetPortalControl().Get(i)
<<" "<<bvh.zmaxs->GetPortalControl().Get(i)
<<" "<<triangleIndices->GetPortalControl().Get(i)
<<" \n";
}
*/
//std::cout<<"\n\n\n";
//sort the morton codes
vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::SortByKey(bvh.mortonCodes, iterator);
vtkm::Id arraySize = bvh.GetNumberOfPrimitives();
vtkm::cont::ArrayHandle<vtkm::Float32>* tempStorage;
vtkm::cont::ArrayHandle<vtkm::Float32>* tempPtr;
//outputTriangleIndices.Allocate( bvh.GetNumberOfPrimitives() );
tempStorage = new vtkm::cont::ArrayHandle<vtkm::Float32>();
//tempStorage->Allocate( arraySize );
// for (int i = 0; i < 12; ++i)
// {
// //std::cout<<bvh.xmins->GetPortalControl().Get(i)<<" ";
// }//std::cout<<"\n";
//xmins
vtkm::worklet::DispatcherMapField<GatherFloat32>(
GatherFloat32(*bvh.xmins, *tempStorage, arraySize))
.Invoke(iterator);
tempPtr = bvh.xmins;
bvh.xmins = tempStorage;
tempStorage = tempPtr;
vtkm::worklet::DispatcherMapField<GatherFloat32>(
GatherFloat32(*bvh.ymins, *tempStorage, arraySize))
.Invoke(iterator);
tempPtr = bvh.ymins;
bvh.ymins = tempStorage;
tempStorage = tempPtr;
//zmins
vtkm::worklet::DispatcherMapField<GatherFloat32>(
GatherFloat32(*bvh.zmins, *tempStorage, arraySize))
.Invoke(iterator);
tempPtr = bvh.zmins;
bvh.zmins = tempStorage;
tempStorage = tempPtr;
//xmaxs
vtkm::worklet::DispatcherMapField<GatherFloat32>(
GatherFloat32(*bvh.xmaxs, *tempStorage, arraySize))
.Invoke(iterator);
tempPtr = bvh.xmaxs;
bvh.xmaxs = tempStorage;
tempStorage = tempPtr;
//ymaxs
vtkm::worklet::DispatcherMapField<GatherFloat32>(
GatherFloat32(*bvh.ymaxs, *tempStorage, arraySize))
.Invoke(iterator);
tempPtr = bvh.ymaxs;
bvh.ymaxs = tempStorage;
tempStorage = tempPtr;
//zmaxs
vtkm::worklet::DispatcherMapField<GatherFloat32>(
GatherFloat32(*bvh.zmaxs, *tempStorage, arraySize))
.Invoke(iterator);
tempPtr = bvh.zmaxs;
bvh.zmaxs = tempStorage;
tempStorage = tempPtr;
vtkm::worklet::DispatcherMapField<GatherVecCast>(
GatherVecCast(triangleIndices, outputTriangleIndices, arraySize))
.Invoke(iterator);
delete tempStorage;
} // method SortAABBs
VTKM_CONT
void run(vtkm::cont::DynamicArrayHandleCoordinateSystem& coordsHandle,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>>& triangleIndices,
const vtkm::Id& numberOfTriangles,
LinearBVH& linearBVH)
{
const vtkm::Id numBBoxes = numberOfTriangles;
BVHData bvh(numBBoxes);
vtkm::worklet::DispatcherMapField<FindAABBs>(FindAABBs())
.Invoke(triangleIndices,
*bvh.xmins,
*bvh.ymins,
*bvh.zmins,
*bvh.xmaxs,
*bvh.ymaxs,
*bvh.zmaxs,
coordsHandle);
// Find the extent of all bounding boxes to generate normalization for morton codes
vtkm::Vec<vtkm::Float32, 3> minExtent(
vtkm::Infinity32(), vtkm::Infinity32(), vtkm::Infinity32());
vtkm::Vec<vtkm::Float32, 3> maxExtent(
vtkm::NegativeInfinity32(), vtkm::NegativeInfinity32(), vtkm::NegativeInfinity32());
maxExtent[0] = vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::Reduce(
*bvh.xmaxs, maxExtent[0], MaxValue());
maxExtent[1] = vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::Reduce(
*bvh.ymaxs, maxExtent[1], MaxValue());
maxExtent[2] = vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::Reduce(
*bvh.zmaxs, maxExtent[2], MaxValue());
minExtent[0] = vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::Reduce(
*bvh.xmins, minExtent[0], MinValue());
minExtent[1] = vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::Reduce(
*bvh.ymins, minExtent[1], MinValue());
minExtent[2] = vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::Reduce(
*bvh.zmins, minExtent[2], MinValue());
vtkm::Vec<vtkm::Float32, 3> deltaExtent = maxExtent - minExtent;
vtkm::Vec<vtkm::Float32, 3> inverseExtent;
for (int i = 0; i < 3; ++i)
{
inverseExtent[i] = (deltaExtent[i] == 0.f) ? 0 : 1.f / deltaExtent[i];
}
//Generate the morton codes
vtkm::worklet::DispatcherMapField<MortonCodeAABB>(MortonCodeAABB(inverseExtent, minExtent))
.Invoke(
*bvh.xmins, *bvh.ymins, *bvh.zmins, *bvh.xmaxs, *bvh.ymaxs, *bvh.zmaxs, bvh.mortonCodes);
linearBVH.Allocate(bvh.GetNumberOfPrimitives(), DeviceAdapter());
SortAABBS(bvh, triangleIndices, linearBVH.LeafNodes);
vtkm::worklet::DispatcherMapField<TreeBuilder>(
TreeBuilder(bvh.mortonCodes, bvh.parent, bvh.GetNumberOfPrimitives()))
.Invoke(bvh.leftChild, bvh.rightChild);
const vtkm::Int32 primitiveCount = vtkm::Int32(bvh.GetNumberOfPrimitives());
vtkm::cont::ArrayHandle<vtkm::Int32> counters;
counters.PrepareForOutput(bvh.GetNumberOfPrimitives() - 1, DeviceAdapter());
vtkm::Int32 zero = 0;
vtkm::worklet::DispatcherMapField<MemSet<vtkm::Int32>>(MemSet<vtkm::Int32>(zero))
.Invoke(counters);
vtkm::exec::AtomicArray<vtkm::Int32, DeviceAdapter> atomicCounters(counters);
vtkm::worklet::DispatcherMapField<PropagateAABBs>(PropagateAABBs(bvh.parent,
bvh.leftChild,
bvh.rightChild,
primitiveCount,
linearBVH.FlatBVH,
atomicCounters))
.Invoke(vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32>(*bvh.xmins),
vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32>(*bvh.ymins),
vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32>(*bvh.zmins),
vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32>(*bvh.xmaxs),
vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32>(*bvh.ymaxs),
vtkm::exec::ExecutionWholeArrayConst<vtkm::Float32>(*bvh.zmaxs));
}
}; // class LinearBVHBuilder
}
}
} // namespace vtkm::rendering::raytracing

@ -21,12 +21,28 @@
set(headers
BoundingVolumeHierarchy.h
Camera.h
ChannelBuffer.h
ChannelBufferOperations.h
ConnectivityBase.h
ConnectivityTracer.h
ConnectivityTracerFactory.h
CellIntersector.h
CellSampler.h
CellTables.h
Logger.h
MeshConnectivityBuilder.h
MeshConnectivityStructures.h
MortonCodes.h
Ray.h
RayOperations.h
RayTracer.h
RayTracingTypeDefs.h
Ray.h
TriangleIntersector.h
Worklets.h
VolumeRendererStructured.h
)
set_source_files_properties(CellTables.h
PROPERTIES VTKm_CANT_BE_HEADER_TESTED TRUE)
vtkm_declare_headers(${headers})

@ -0,0 +1,929 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/rendering/raytracing/Camera.h>
#include <vtkm/rendering/raytracing/RayOperations.h>
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
class PixelData : public vtkm::worklet::WorkletMapField
{
public:
vtkm::Int32 w;
vtkm::Int32 h;
vtkm::Int32 Minx;
vtkm::Int32 Miny;
vtkm::Int32 SubsetWidth;
vtkm::Vec<vtkm::Float32, 3> nlook; // normalized look
vtkm::Vec<vtkm::Float32, 3> delta_x;
vtkm::Vec<vtkm::Float32, 3> delta_y;
vtkm::Vec<vtkm::Float32, 3> Origin;
vtkm::Bounds BoundingBox;
VTKM_CONT
PixelData(vtkm::Int32 width,
vtkm::Int32 height,
vtkm::Float32 fovX,
vtkm::Float32 fovY,
vtkm::Vec<vtkm::Float32, 3> look,
vtkm::Vec<vtkm::Float32, 3> up,
vtkm::Float32 _zoom,
vtkm::Int32 subsetWidth,
vtkm::Int32 minx,
vtkm::Int32 miny,
vtkm::Vec<vtkm::Float32, 3> origin,
vtkm::Bounds boundingBox)
: w(width)
, h(height)
, Minx(minx)
, Miny(miny)
, SubsetWidth(subsetWidth)
, Origin(origin)
, BoundingBox(boundingBox)
{
vtkm::Float32 thx = tanf((fovX * vtkm::Float32(vtkm::Pi()) / 180.f) * .5f);
vtkm::Float32 thy = tanf((fovY * vtkm::Float32(vtkm::Pi()) / 180.f) * .5f);
vtkm::Vec<vtkm::Float32, 3> ru = vtkm::Cross(look, up);
vtkm::Normalize(ru);
vtkm::Vec<vtkm::Float32, 3> rv = vtkm::Cross(ru, look);
vtkm::Normalize(rv);
delta_x = ru * (2 * thx / (float)w);
delta_y = rv * (2 * thy / (float)h);
if (_zoom > 0)
{
delta_x[0] = delta_x[0] / _zoom;
delta_x[1] = delta_x[1] / _zoom;
delta_x[2] = delta_x[2] / _zoom;
delta_y[0] = delta_y[0] / _zoom;
delta_y[1] = delta_y[1] / _zoom;
delta_y[2] = delta_y[2] / _zoom;
}
nlook = look;
vtkm::Normalize(nlook);
}
VTKM_EXEC inline vtkm::Float32 rcp(vtkm::Float32 f) const { return 1.0f / f; }
VTKM_EXEC inline vtkm::Float32 rcp_safe(vtkm::Float32 f) const
{
return rcp((fabs(f) < 1e-8f) ? 1e-8f : f);
}
typedef void ControlSignature(FieldOut<>, FieldOut<>);
typedef void ExecutionSignature(WorkIndex, _1, _2);
VTKM_EXEC
void operator()(const vtkm::Id idx, vtkm::Int32& hit, vtkm::Float32& distance) const
{
vtkm::Vec<vtkm::Float32, 3> ray_dir;
int i = vtkm::Int32(idx) % SubsetWidth;
int j = vtkm::Int32(idx) / SubsetWidth;
i += Minx;
j += Miny;
// Write out the global pixelId
ray_dir = nlook + delta_x * ((2.f * vtkm::Float32(i) - vtkm::Float32(w)) / 2.0f) +
delta_y * ((2.f * vtkm::Float32(j) - vtkm::Float32(h)) / 2.0f);
vtkm::Float32 dot = vtkm::dot(ray_dir, ray_dir);
vtkm::Float32 sq_mag = vtkm::Sqrt(dot);
ray_dir[0] = ray_dir[0] / sq_mag;
ray_dir[1] = ray_dir[1] / sq_mag;
ray_dir[2] = ray_dir[2] / sq_mag;
vtkm::Float32 invDirx = rcp_safe(ray_dir[0]);
vtkm::Float32 invDiry = rcp_safe(ray_dir[1]);
vtkm::Float32 invDirz = rcp_safe(ray_dir[2]);
vtkm::Float32 odirx = Origin[0] * invDirx;
vtkm::Float32 odiry = Origin[1] * invDiry;
vtkm::Float32 odirz = Origin[2] * invDirz;
vtkm::Float32 xmin = vtkm::Float32(BoundingBox.X.Min) * invDirx - odirx;
vtkm::Float32 ymin = vtkm::Float32(BoundingBox.Y.Min) * invDiry - odiry;
vtkm::Float32 zmin = vtkm::Float32(BoundingBox.Z.Min) * invDirz - odirz;
vtkm::Float32 xmax = vtkm::Float32(BoundingBox.X.Max) * invDirx - odirx;
vtkm::Float32 ymax = vtkm::Float32(BoundingBox.Y.Max) * invDiry - odiry;
vtkm::Float32 zmax = vtkm::Float32(BoundingBox.Z.Max) * invDirz - odirz;
vtkm::Float32 mind = vtkm::Max(
vtkm::Max(vtkm::Max(vtkm::Min(ymin, ymax), vtkm::Min(xmin, xmax)), vtkm::Min(zmin, zmax)),
0.f);
vtkm::Float32 maxd =
vtkm::Min(vtkm::Min(vtkm::Max(ymin, ymax), vtkm::Max(xmin, xmax)), vtkm::Max(zmin, zmax));
if (maxd < mind)
{
hit = 0;
distance = 0;
}
else
{
distance = maxd - mind;
hit = 1;
}
}
}; // class pixelData
class Camera::PerspectiveRayGen : public vtkm::worklet::WorkletMapField
{
public:
vtkm::Int32 w;
vtkm::Int32 h;
vtkm::Int32 Minx;
vtkm::Int32 Miny;
vtkm::Int32 SubsetWidth;
vtkm::Vec<vtkm::Float32, 3> nlook; // normalized look
vtkm::Vec<vtkm::Float32, 3> delta_x;
vtkm::Vec<vtkm::Float32, 3> delta_y;
VTKM_CONT
PerspectiveRayGen(vtkm::Int32 width,
vtkm::Int32 height,
vtkm::Float32 fovX,
vtkm::Float32 fovY,
vtkm::Vec<vtkm::Float32, 3> look,
vtkm::Vec<vtkm::Float32, 3> up,
vtkm::Float32 _zoom,
vtkm::Int32 subsetWidth,
vtkm::Int32 minx,
vtkm::Int32 miny)
: w(width)
, h(height)
, Minx(minx)
, Miny(miny)
, SubsetWidth(subsetWidth)
{
vtkm::Float32 thx = tanf((fovX * vtkm::Float32(vtkm::Pi()) / 180.f) * .5f);
vtkm::Float32 thy = tanf((fovY * vtkm::Float32(vtkm::Pi()) / 180.f) * .5f);
vtkm::Vec<vtkm::Float32, 3> ru = vtkm::Cross(look, up);
vtkm::Normalize(ru);
vtkm::Vec<vtkm::Float32, 3> rv = vtkm::Cross(ru, look);
vtkm::Normalize(rv);
delta_x = ru * (2 * thx / (float)w);
delta_y = rv * (2 * thy / (float)h);
if (_zoom > 0)
{
delta_x[0] = delta_x[0] / _zoom;
delta_x[1] = delta_x[1] / _zoom;
delta_x[2] = delta_x[2] / _zoom;
delta_y[0] = delta_y[0] / _zoom;
delta_y[1] = delta_y[1] / _zoom;
delta_y[2] = delta_y[2] / _zoom;
}
nlook = look;
vtkm::Normalize(nlook);
}
typedef void ControlSignature(FieldOut<>, FieldOut<>, FieldOut<>, FieldOut<>);
typedef void ExecutionSignature(WorkIndex, _1, _2, _3, _4);
template <typename Precision>
VTKM_EXEC void operator()(vtkm::Id idx,
Precision& rayDirX,
Precision& rayDirY,
Precision& rayDirZ,
vtkm::Id& pixelIndex) const
{
vtkm::Vec<Precision, 3> ray_dir(rayDirX, rayDirY, rayDirZ);
int i = vtkm::Int32(idx) % SubsetWidth;
int j = vtkm::Int32(idx) / SubsetWidth;
i += Minx;
j += Miny;
// Write out the global pixelId
pixelIndex = static_cast<vtkm::Id>(j * w + i);
ray_dir = nlook + delta_x * ((2.f * Precision(i) - Precision(w)) / 2.0f) +
delta_y * ((2.f * Precision(j) - Precision(h)) / 2.0f);
Precision dot = vtkm::dot(ray_dir, ray_dir);
Precision sq_mag = vtkm::Sqrt(dot);
rayDirX = ray_dir[0] / sq_mag;
rayDirY = ray_dir[1] / sq_mag;
rayDirZ = ray_dir[2] / sq_mag;
}
}; // class perspective ray gen
bool Camera::operator==(const Camera& other) const
{
if (this->Height != other.Height)
return false;
if (this->Width != other.Width)
return false;
if (this->SubsetWidth != other.SubsetWidth)
return false;
if (this->SubsetHeight != other.SubsetHeight)
return false;
if (this->SubsetMinX != other.SubsetMinX)
return false;
if (this->SubsetMinY != other.SubsetMinY)
return false;
if (this->FovY != other.FovY)
return false;
if (this->FovX != other.FovX)
return false;
if (this->Zoom != other.Zoom)
return false;
if (this->Look[0] != other.Look[0])
return false;
if (this->Look[1] != other.Look[1])
return false;
if (this->Look[2] != other.Look[2])
return false;
if (this->LookAt[0] != other.LookAt[0])
return false;
if (this->LookAt[1] != other.LookAt[1])
return false;
if (this->LookAt[2] != other.LookAt[2])
return false;
if (this->Up[0] != other.Up[0])
return false;
if (this->Up[1] != other.Up[1])
return false;
if (this->Up[2] != other.Up[2])
return false;
if (this->Position[0] != other.Position[0])
return false;
if (this->Position[1] != other.Position[1])
return false;
if (this->Position[2] != other.Position[2])
return false;
return true;
}
VTKM_CONT
Camera::Camera()
{
this->Height = 500;
this->Width = 500;
this->SubsetWidth = 500;
this->SubsetHeight = 500;
this->SubsetMinX = 0;
this->SubsetMinY = 0;
this->FovY = 30.f;
this->FovX = 30.f;
this->Zoom = 1.f;
this->Look[0] = 0.f;
this->Look[1] = 0.f;
this->Look[2] = -1.f;
this->LookAt[0] = 0.f;
this->LookAt[1] = 0.f;
this->LookAt[2] = -1.f;
this->Up[0] = 0.f;
this->Up[1] = 1.f;
this->Up[2] = 0.f;
this->Position[0] = 0.f;
this->Position[1] = 0.f;
this->Position[2] = 0.f;
this->IsViewDirty = true;
}
VTKM_CONT
Camera::~Camera()
{
}
VTKM_CONT
void Camera::SetParameters(const vtkm::rendering::Camera& camera,
vtkm::rendering::CanvasRayTracer& canvas)
{
this->SetUp(camera.GetViewUp());
this->SetLookAt(camera.GetLookAt());
this->SetPosition(camera.GetPosition());
this->SetFieldOfView(camera.GetFieldOfView());
this->SetHeight(static_cast<vtkm::Int32>(canvas.GetHeight()));
this->SetWidth(static_cast<vtkm::Int32>(canvas.GetWidth()));
this->CameraView = camera;
Canvas = canvas;
}
VTKM_CONT
void Camera::SetHeight(const vtkm::Int32& height)
{
if (height <= 0)
{
throw vtkm::cont::ErrorBadValue("Camera height must be greater than zero.");
}
if (Height != height)
{
this->Height = height;
this->SetFieldOfView(this->FovX);
}
}
VTKM_CONT
vtkm::Int32 Camera::GetHeight() const
{
return this->Height;
}
VTKM_CONT
void Camera::SetWidth(const vtkm::Int32& width)
{
if (width <= 0)
{
throw vtkm::cont::ErrorBadValue("Camera width must be greater than zero.");
}
if (this->Width != width)
{
this->Width = width;
this->SetFieldOfView(this->FovX);
}
}
VTKM_CONT
vtkm::Int32 Camera::GetWidth() const
{
return this->Width;
}
VTKM_CONT
vtkm::Int32 Camera::GetSubsetWidth() const
{
return this->SubsetWidth;
}
VTKM_CONT
vtkm::Int32 Camera::GetSubsetHeight() const
{
return this->SubsetHeight;
}
VTKM_CONT
void Camera::SetZoom(const vtkm::Float32& zoom)
{
if (zoom <= 0)
{
throw vtkm::cont::ErrorBadValue("Camera zoom must be greater than zero.");
}
if (this->Zoom != zoom)
{
this->IsViewDirty = true;
this->Zoom = zoom;
}
}
VTKM_CONT
vtkm::Float32 Camera::GetZoom() const
{
return this->Zoom;
}
VTKM_CONT
void Camera::SetFieldOfView(const vtkm::Float32& degrees)
{
if (degrees <= 0)
{
throw vtkm::cont::ErrorBadValue("Camera feild of view must be greater than zero.");
}
if (degrees > 180)
{
throw vtkm::cont::ErrorBadValue("Camera feild of view must be less than 180.");
}
vtkm::Float32 newFOVY = (vtkm::Float32(this->Height) / vtkm::Float32(this->Width)) * degrees;
vtkm::Float32 newFOVX = degrees;
if (newFOVX != this->FovX)
{
this->IsViewDirty = true;
}
if (newFOVY != this->FovY)
{
this->IsViewDirty = true;
}
this->FovX = newFOVX;
this->FovY = newFOVY;
this->CameraView.SetFieldOfView(this->FovX);
}
VTKM_CONT
vtkm::Float32 Camera::GetFieldOfView() const
{
return this->FovX;
}
VTKM_CONT
void Camera::SetUp(const vtkm::Vec<vtkm::Float32, 3>& up)
{
if (this->Up != up)
{
this->Up = up;
vtkm::Normalize(this->Up);
this->IsViewDirty = true;
}
}
VTKM_CONT
vtkm::Vec<vtkm::Float32, 3> Camera::GetUp() const
{
return this->Up;
}
VTKM_CONT
void Camera::SetLookAt(const vtkm::Vec<vtkm::Float32, 3>& lookAt)
{
if (this->LookAt != lookAt)
{
this->LookAt = lookAt;
this->IsViewDirty = true;
}
}
VTKM_CONT
vtkm::Vec<vtkm::Float32, 3> Camera::GetLookAt() const
{
return this->LookAt;
}
VTKM_CONT
void Camera::SetPosition(const vtkm::Vec<vtkm::Float32, 3>& position)
{
if (this->Position != position)
{
this->Position = position;
this->IsViewDirty = true;
}
}
VTKM_CONT
vtkm::Vec<vtkm::Float32, 3> Camera::GetPosition() const
{
return this->Position;
}
VTKM_CONT
void Camera::ResetIsViewDirty()
{
this->IsViewDirty = false;
}
VTKM_CONT
bool Camera::GetIsViewDirty() const
{
return this->IsViewDirty;
}
template <typename Precision>
struct Camera::CreateRaysFunctor
{
vtkm::rendering::raytracing::Camera* Self;
const vtkm::cont::CoordinateSystem& Coords;
vtkm::rendering::raytracing::Ray<Precision>& Rays;
VTKM_CONT
CreateRaysFunctor(vtkm::rendering::raytracing::Camera* self,
const vtkm::cont::CoordinateSystem& coords,
vtkm::rendering::raytracing::Ray<Precision>& rays)
: Self(self)
, Coords(coords)
, Rays(rays)
{
}
template <typename Device>
VTKM_CONT bool operator()(Device)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::Bounds boundingBox = Coords.GetBounds();
Self->CreateRaysOnDevice(this->Rays, Device(), boundingBox);
return true;
}
};
struct Camera::PixelDataFunctor
{
vtkm::rendering::raytracing::Camera* Self;
const vtkm::cont::CoordinateSystem& Coords;
vtkm::Int32& ActivePixels;
vtkm::Float32& AveDistPerRay;
VTKM_CONT
PixelDataFunctor(vtkm::rendering::raytracing::Camera* self,
const vtkm::cont::CoordinateSystem& coords,
vtkm::Int32& activePixels,
vtkm::Float32& aveDistPerRay)
: Self(self)
, Coords(coords)
, ActivePixels(activePixels)
, AveDistPerRay(aveDistPerRay)
{
}
template <typename Device>
VTKM_CONT bool operator()(Device)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::Bounds boundingBox = Coords.GetBounds();
Self->FindSubset(boundingBox);
//Reset the camera look vector
Self->Look = Self->LookAt - Self->Position;
vtkm::Normalize(Self->Look);
const int size = Self->SubsetWidth * Self->SubsetHeight;
vtkm::cont::ArrayHandle<vtkm::Float32> dists;
vtkm::cont::ArrayHandle<vtkm::Int32> hits;
dists.PrepareForOutput(size, Device());
hits.PrepareForOutput(size, Device());
//Create the ray direction
vtkm::worklet::DispatcherMapField<PixelData, Device>(PixelData(Self->Width,
Self->Height,
Self->FovX,
Self->FovY,
Self->Look,
Self->Up,
Self->Zoom,
Self->SubsetWidth,
Self->SubsetMinX,
Self->SubsetMinY,
Self->Position,
boundingBox))
.Invoke(hits, dists); //X Y Z
ActivePixels = vtkm::cont::DeviceAdapterAlgorithm<Device>::Reduce(hits, vtkm::Int32(0));
AveDistPerRay = vtkm::cont::DeviceAdapterAlgorithm<Device>::Reduce(dists, vtkm::Float32(0)) /
vtkm::Float32(ActivePixels);
return true;
}
};
void Camera::GetPixelData(const vtkm::cont::CoordinateSystem& coords,
vtkm::Int32& activePixels,
vtkm::Float32& aveRayDistance)
{
PixelDataFunctor functor(this, coords, activePixels, aveRayDistance);
vtkm::cont::TryExecute(functor);
}
VTKM_CONT
void Camera::CreateRays(Ray<vtkm::Float32>& rays, const vtkm::cont::CoordinateSystem& coords)
{
CreateRaysFunctor<Float32> functor(this, coords, rays);
vtkm::cont::TryExecute(functor);
}
VTKM_CONT
void Camera::CreateRays(Ray<vtkm::Float64>& rays, const vtkm::cont::CoordinateSystem& coords)
{
CreateRaysFunctor<Float64> functor(this, coords, rays);
vtkm::cont::TryExecute(functor);
}
template <typename Precision, typename Device>
VTKM_CONT void Camera::CreateRaysOnDevice(Ray<Precision>& rays,
Device,
const vtkm::Bounds boundingBox)
{
Logger* logger = Logger::GetInstance();
vtkm::cont::Timer<Device> createTimer;
logger->OpenLogEntry("ray_camera");
logger->AddLogData("device", GetDeviceString(Device()));
this->UpdateDimensions(rays, Device(), boundingBox);
this->WriteSettingsToLog();
vtkm::cont::Timer<Device> timer;
//Set the origin of the ray back to the camera position
vtkm::worklet::DispatcherMapField<MemSet<Precision>, Device>(MemSet<Precision>(this->Position[0]))
.Invoke(rays.OriginX);
vtkm::worklet::DispatcherMapField<MemSet<Precision>, Device>(MemSet<Precision>(this->Position[1]))
.Invoke(rays.OriginY);
vtkm::worklet::DispatcherMapField<MemSet<Precision>, Device>(MemSet<Precision>(this->Position[2]))
.Invoke(rays.OriginZ);
Precision infinity;
GetInfinity(infinity);
vtkm::worklet::DispatcherMapField<MemSet<Precision>, Device>(MemSet<Precision>(infinity))
.Invoke(rays.MaxDistance);
vtkm::worklet::DispatcherMapField<MemSet<Precision>, Device>(MemSet<Precision>(0.f))
.Invoke(rays.MinDistance);
//Reset the Rays Hit Index to -2
vtkm::worklet::DispatcherMapField<MemSet<vtkm::Id>, Device>(MemSet<vtkm::Id>(-2))
.Invoke(rays.HitIdx);
vtkm::Float64 time = timer.GetElapsedTime();
logger->AddLogData("camera_memset", time);
timer.Reset();
//Reset the camera look vector
this->Look = this->LookAt - this->Position;
vtkm::Normalize(this->Look);
//Create the ray direction
vtkm::worklet::DispatcherMapField<PerspectiveRayGen, Device>(PerspectiveRayGen(this->Width,
this->Height,
this->FovX,
this->FovY,
this->Look,
this->Up,
this->Zoom,
this->SubsetWidth,
this->SubsetMinX,
this->SubsetMinY))
.Invoke(rays.DirX,
rays.DirY,
rays.DirZ,
rays.PixelIdx); //X Y Z
time = timer.GetElapsedTime();
logger->AddLogData("ray_gen", time);
time = createTimer.GetElapsedTime();
logger->CloseLogEntry(time);
} //create rays
VTKM_CONT
void Camera::FindSubset(const vtkm::Bounds& bounds)
{
this->ViewProjectionMat =
vtkm::MatrixMultiply(this->CameraView.CreateProjectionMatrix(this->Width, this->Height),
this->CameraView.CreateViewMatrix());
vtkm::Float32 x[2], y[2], z[2];
x[0] = static_cast<vtkm::Float32>(bounds.X.Min);
x[1] = static_cast<vtkm::Float32>(bounds.X.Max);
y[0] = static_cast<vtkm::Float32>(bounds.Y.Min);
y[1] = static_cast<vtkm::Float32>(bounds.Y.Max);
z[0] = static_cast<vtkm::Float32>(bounds.Z.Min);
z[1] = static_cast<vtkm::Float32>(bounds.Z.Max);
//Inise the data bounds
if (this->Position[0] >= x[0] && this->Position[0] <= x[1] && this->Position[1] >= y[0] &&
this->Position[1] <= y[1] && this->Position[2] >= z[0] && this->Position[2] <= z[1])
{
this->SubsetWidth = this->Width;
this->SubsetHeight = this->Height;
this->SubsetMinY = 0;
this->SubsetMinX = 0;
return;
}
//std::cout<<"Bounds ("<<x[0]<<","<<y[0]<<","<<z[0]<<")-("<<x[1]<<","<<y[1]<<","<<z[1]<<std::endl;
vtkm::Float32 xmin, ymin, xmax, ymax, zmin, zmax;
xmin = vtkm::Infinity32();
ymin = vtkm::Infinity32();
zmin = vtkm::Infinity32();
xmax = vtkm::NegativeInfinity32();
ymax = vtkm::NegativeInfinity32();
zmax = vtkm::NegativeInfinity32();
vtkm::Vec<vtkm::Float32, 4> extentPoint;
for (vtkm::Int32 i = 0; i < 2; ++i)
for (vtkm::Int32 j = 0; j < 2; ++j)
for (vtkm::Int32 k = 0; k < 2; ++k)
{
extentPoint[0] = x[i];
extentPoint[1] = y[j];
extentPoint[2] = z[k];
extentPoint[3] = 1.f;
vtkm::Vec<vtkm::Float32, 4> transformed =
vtkm::MatrixMultiply(this->ViewProjectionMat, extentPoint);
// perform the perspective divide
for (vtkm::Int32 a = 0; a < 3; ++a)
{
transformed[a] = transformed[a] / transformed[3];
}
transformed[0] = (transformed[0] * 0.5f + 0.5f) * static_cast<vtkm::Float32>(Width);
transformed[1] = (transformed[1] * 0.5f + 0.5f) * static_cast<vtkm::Float32>(Height);
transformed[2] = (transformed[2] * 0.5f + 0.5f);
zmin = vtkm::Min(zmin, transformed[2]);
zmax = vtkm::Max(zmax, transformed[2]);
if (transformed[2] < 0 || transformed[2] > 1)
{
continue;
}
xmin = vtkm::Min(xmin, transformed[0]);
ymin = vtkm::Min(ymin, transformed[1]);
xmax = vtkm::Max(xmax, transformed[0]);
ymax = vtkm::Max(ymax, transformed[1]);
}
xmin -= .001f;
xmax += .001f;
ymin -= .001f;
ymax += .001f;
xmin = vtkm::Floor(vtkm::Min(vtkm::Max(0.f, xmin), vtkm::Float32(Width)));
xmax = vtkm::Ceil(vtkm::Min(vtkm::Max(0.f, xmax), vtkm::Float32(Width)));
ymin = vtkm::Floor(vtkm::Min(vtkm::Max(0.f, ymin), vtkm::Float32(Height)));
ymax = vtkm::Ceil(vtkm::Min(vtkm::Max(0.f, ymax), vtkm::Float32(Height)));
//printf("Pixel range = (%f,%f,%f), (%f,%f,%f)\n", xmin, ymin,zmin, xmax,ymax,zmax);
vtkm::Int32 dx = vtkm::Int32(xmax) - vtkm::Int32(xmin);
vtkm::Int32 dy = vtkm::Int32(ymax) - vtkm::Int32(ymin);
//
// scene is behind the camera
//
if (zmax < 0 || xmin >= xmax || ymin >= ymax)
{
this->SubsetWidth = 1;
this->SubsetHeight = 1;
this->SubsetMinX = 0;
this->SubsetMinY = 0;
}
else
{
this->SubsetWidth = dx;
this->SubsetHeight = dy;
this->SubsetMinX = vtkm::Int32(xmin);
this->SubsetMinY = vtkm::Int32(ymin);
}
}
template <typename Device, typename Precision>
VTKM_CONT void Camera::UpdateDimensions(Ray<Precision>& rays,
Device,
const vtkm::Bounds& boundingBox)
{
// If bounds have been provided, only cast rays that could hit the data
bool imageSubsetModeOn = boundingBox.IsNonEmpty();
//Create a transform matrix using the rendering::camera class
vtkm::rendering::Camera camera;
camera.SetFieldOfView(this->GetFieldOfView());
camera.SetLookAt(this->GetLookAt());
camera.SetPosition(this->GetPosition());
camera.SetViewUp(this->GetUp());
//
// Just create come clipping range, we ignore the zmax value in subsetting
//
vtkm::Float64 maxDim = vtkm::Max(
boundingBox.X.Max - boundingBox.X.Min,
vtkm::Max(boundingBox.Y.Max - boundingBox.Y.Min, boundingBox.Z.Max - boundingBox.Z.Min));
maxDim *= 100;
camera.SetClippingRange(.0001, maxDim);
this->CameraView = camera;
//Update our ViewProjection matrix
this->ViewProjectionMat =
vtkm::MatrixMultiply(this->CameraView.CreateProjectionMatrix(this->Width, this->Height),
this->CameraView.CreateViewMatrix());
//Find the pixel footprint
if (imageSubsetModeOn)
{
this->FindSubset(boundingBox);
}
//Update the image dimensions
this->SubsetWidth = this->Width;
this->SubsetHeight = this->Height;
this->SubsetMinY = 0;
this->SubsetMinX = 0;
// resize rays and buffers
if (rays.NumRays != SubsetWidth * SubsetHeight)
{
RayOperations::Resize(rays, this->SubsetHeight * this->SubsetWidth, Device());
}
}
void Camera::CreateDebugRay(vtkm::Vec<vtkm::Int32, 2> pixel, Ray<vtkm::Float64>& rays)
{
CreateDebugRayImp(pixel, rays);
}
void Camera::CreateDebugRay(vtkm::Vec<vtkm::Int32, 2> pixel, Ray<vtkm::Float32>& rays)
{
CreateDebugRayImp(pixel, rays);
}
template <typename Precision>
void Camera::CreateDebugRayImp(vtkm::Vec<vtkm::Int32, 2> pixel, Ray<Precision>& rays)
{
RayOperations::Resize(rays, 1, vtkm::cont::DeviceAdapterTagSerial());
vtkm::Int32 pixelIndex = this->Width * (this->Height - pixel[1]) + pixel[0];
rays.PixelIdx.GetPortalControl().Set(0, pixelIndex);
rays.OriginX.GetPortalControl().Set(0, this->Position[0]);
rays.OriginY.GetPortalControl().Set(0, this->Position[1]);
rays.OriginZ.GetPortalControl().Set(0, this->Position[2]);
vtkm::Float32 infinity;
GetInfinity(infinity);
rays.MaxDistance.GetPortalControl().Set(0, infinity);
rays.MinDistance.GetPortalControl().Set(0, 0.f);
rays.HitIdx.GetPortalControl().Set(0, -2);
vtkm::Float32 thx = tanf((this->FovX * vtkm::Float32(vtkm::Pi()) / 180.f) * .5f);
vtkm::Float32 thy = tanf((this->FovY * vtkm::Float32(vtkm::Pi()) / 180.f) * .5f);
vtkm::Vec<vtkm::Float32, 3> ru = vtkm::Cross(this->Look, this->Up);
vtkm::Normalize(ru);
vtkm::Vec<vtkm::Float32, 3> rv = vtkm::Cross(ru, this->Look);
vtkm::Vec<vtkm::Float32, 3> delta_x, delta_y;
vtkm::Normalize(rv);
delta_x = ru * (2 * thx / (float)this->Width);
delta_y = rv * (2 * thy / (float)this->Height);
if (this->Zoom > 0)
{
vtkm::Float32 _zoom = this->Zoom;
delta_x[0] = delta_x[0] / _zoom;
delta_x[1] = delta_x[1] / _zoom;
delta_x[2] = delta_x[2] / _zoom;
delta_y[0] = delta_y[0] / _zoom;
delta_y[1] = delta_y[1] / _zoom;
delta_y[2] = delta_y[2] / _zoom;
}
vtkm::Vec<vtkm::Float32, 3> nlook = this->Look;
vtkm::Normalize(nlook);
vtkm::Vec<Precision, 3> ray_dir;
int i = vtkm::Int32(pixelIndex) % this->Width;
int j = vtkm::Int32(pixelIndex) / this->Height;
ray_dir = nlook + delta_x * ((2.f * Precision(i) - Precision(this->Width)) / 2.0f) +
delta_y * ((2.f * Precision(j) - Precision(this->Height)) / 2.0f);
Precision dot = vtkm::dot(ray_dir, ray_dir);
Precision sq_mag = vtkm::Sqrt(dot);
ray_dir[0] = ray_dir[0] / sq_mag;
ray_dir[1] = ray_dir[1] / sq_mag;
ray_dir[2] = ray_dir[2] / sq_mag;
rays.DirX.GetPortalControl().Set(0, ray_dir[0]);
rays.DirY.GetPortalControl().Set(0, ray_dir[1]);
rays.DirZ.GetPortalControl().Set(0, ray_dir[2]);
}
void Camera::WriteSettingsToLog()
{
Logger* logger = Logger::GetInstance();
logger->AddLogData("position_x", Position[0]);
logger->AddLogData("position_y", Position[1]);
logger->AddLogData("position_z", Position[2]);
logger->AddLogData("lookat_x", LookAt[0]);
logger->AddLogData("lookat_y", LookAt[1]);
logger->AddLogData("lookat_z", LookAt[2]);
logger->AddLogData("up_x", Up[0]);
logger->AddLogData("up_y", Up[1]);
logger->AddLogData("up_z", Up[2]);
logger->AddLogData("fov_x", FovX);
logger->AddLogData("fov_y", FovY);
logger->AddLogData("width", Width);
logger->AddLogData("height", Height);
logger->AddLogData("subset_height", SubsetHeight);
logger->AddLogData("subset_width", SubsetWidth);
logger->AddLogData("num_rays", SubsetWidth * SubsetHeight);
}
std::string Camera::ToString()
{
std::stringstream sstream;
sstream << "------------------------------------------------------------\n";
sstream << "Position : [" << this->Position[0] << ",";
sstream << this->Position[1] << ",";
sstream << this->Position[2] << "]\n";
sstream << "LookAt : [" << this->LookAt[0] << ",";
sstream << this->LookAt[1] << ",";
sstream << this->LookAt[2] << "]\n";
sstream << "FOV_X : " << this->FovX << "\n";
sstream << "Up : [" << this->Up[0] << ",";
sstream << this->Up[1] << ",";
sstream << this->Up[2] << "]\n";
sstream << "Width : " << this->Width << "\n";
sstream << "Height : " << this->Height << "\n";
sstream << "------------------------------------------------------------\n";
return sstream.str();
}
}
}
} //namespace vtkm::rendering::raytracing

@ -21,9 +21,11 @@
#define vtk_m_rendering_raytracing_Camera_h
#include <vtkm/VectorAnalysis.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/CoordinateSystem.h>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/rendering/Camera.h>
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/rendering/raytracing/Logger.h>
#include <vtkm/rendering/raytracing/Ray.h>
#include <vtkm/rendering/raytracing/RayTracingTypeDefs.h>
#include <vtkm/rendering/raytracing/Worklets.h>
@ -38,138 +40,15 @@ namespace rendering
{
namespace raytracing
{
template <typename DeviceAdapter>
class Camera
class VTKM_RENDERING_EXPORT Camera
{
public:
class SurfaceConverter : public vtkm::worklet::WorkletMapField
{
vtkm::Float32 Proj22;
vtkm::Float32 Proj23;
vtkm::Float32 Proj32;
vtkm::Int32 Width;
vtkm::Int32 SubsetWidth;
vtkm::Int32 Xmin;
vtkm::Int32 Ymin;
vtkm::Int32 NumPixels;
public:
VTKM_CONT
SurfaceConverter(const vtkm::Int32& width,
const vtkm::Int32& subsetWidth,
const vtkm::Int32& xmin,
const vtkm::Int32& ymin,
const vtkm::Matrix<vtkm::Float32, 4, 4> projMat,
const vtkm::Int32& numPixels)
{
Width = width;
SubsetWidth = subsetWidth;
Xmin = xmin;
Ymin = ymin;
Proj22 = projMat[2][2];
Proj23 = projMat[2][3];
Proj32 = projMat[3][2];
NumPixels = numPixels;
}
typedef void ControlSignature(FieldIn<>, FieldIn<>, ExecObject, ExecObject);
typedef void ExecutionSignature(_1, _2, _3, _4, WorkIndex);
VTKM_EXEC
void operator()(const vtkm::Vec<vtkm::Float32, 4>& inColor,
const vtkm::Float32& inDepth,
vtkm::exec::ExecutionWholeArray<vtkm::Float32>& depthBuffer,
vtkm::exec::ExecutionWholeArray<vtkm::Vec<vtkm::Float32, 4>>& colorBuffer,
const vtkm::Id& index) const
{
if (index >= NumPixels)
return;
vtkm::Float32 depth = (Proj22 + Proj23 / (-inDepth)) / Proj32;
depth = 0.5f * depth + 0.5f;
vtkm::Int32 x = static_cast<vtkm::Int32>(index) % SubsetWidth;
vtkm::Int32 y = static_cast<vtkm::Int32>(index) / SubsetWidth;
x += Xmin;
y += Ymin;
vtkm::Id outIdx = static_cast<vtkm::Id>(y * Width + x);
//std::cout<<" "<<depth;
depthBuffer.Set(outIdx, depth);
colorBuffer.Set(outIdx, inColor);
}
}; //class SurfaceConverter
class PerspectiveRayGen : public vtkm::worklet::WorkletMapField
{
public:
vtkm::Int32 w;
vtkm::Int32 h;
vtkm::Int32 Minx;
vtkm::Int32 Miny;
vtkm::Int32 SubsetWidth;
vtkm::Vec<vtkm::Float32, 3> nlook; // normalized look
vtkm::Vec<vtkm::Float32, 3> delta_x;
vtkm::Vec<vtkm::Float32, 3> delta_y;
VTKM_CONT
PerspectiveRayGen(vtkm::Int32 width,
vtkm::Int32 height,
vtkm::Float32 fovX,
vtkm::Float32 fovY,
vtkm::Vec<vtkm::Float32, 3> look,
vtkm::Vec<vtkm::Float32, 3> up,
vtkm::Float32 _zoom,
vtkm::Int32 subsetWidth,
vtkm::Int32 minx,
vtkm::Int32 miny)
: w(width)
, h(height)
, Minx(minx)
, Miny(miny)
, SubsetWidth(subsetWidth)
{
vtkm::Float32 thx = tanf((fovX * vtkm::Float32(vtkm::Pi()) / 180.f) * .5f);
vtkm::Float32 thy = tanf((fovY * vtkm::Float32(vtkm::Pi()) / 180.f) * .5f);
vtkm::Vec<vtkm::Float32, 3> ru = vtkm::Cross(look, up);
vtkm::Normalize(ru);
vtkm::Vec<vtkm::Float32, 3> rv = vtkm::Cross(ru, look);
vtkm::Normalize(rv);
delta_x = ru * (2 * thx / (float)w);
delta_y = rv * (2 * thy / (float)h);
if (_zoom > 0)
{
delta_x[0] = delta_x[0] / _zoom;
delta_x[1] = delta_x[1] / _zoom;
delta_x[2] = delta_x[2] / _zoom;
delta_y[0] = delta_y[0] / _zoom;
delta_y[1] = delta_y[1] / _zoom;
delta_y[2] = delta_y[2] / _zoom;
}
nlook = look;
vtkm::Normalize(nlook);
}
typedef void ControlSignature(FieldOut<>, FieldOut<>, FieldOut<>);
typedef void ExecutionSignature(WorkIndex, _1, _2, _3);
VTKM_EXEC
void operator()(vtkm::Id idx,
vtkm::Float32& rayDirX,
vtkm::Float32& rayDirY,
vtkm::Float32& rayDirZ) const
{
vtkm::Vec<vtkm::Float32, 3> ray_dir(rayDirX, rayDirY, rayDirZ);
int i = vtkm::Int32(idx) % SubsetWidth;
int j = vtkm::Int32(idx) / SubsetWidth;
i += Minx;
j += Miny;
ray_dir = nlook + delta_x * ((2.f * vtkm::Float32(i) - vtkm::Float32(w)) / 2.0f) +
delta_y * ((2.f * vtkm::Float32(j) - vtkm::Float32(h)) / 2.0f);
vtkm::Normalize(ray_dir);
rayDirX = ray_dir[0];
rayDirY = ray_dir[1];
rayDirZ = ray_dir[2];
}
}; // class perspective ray gen
private:
struct PixelDataFunctor;
template <typename Precision>
struct CreateRaysFunctor;
vtkm::rendering::CanvasRayTracer Canvas;
vtkm::Int32 Height;
vtkm::Int32 Width;
vtkm::Int32 SubsetWidth;
@ -178,13 +57,8 @@ private:
vtkm::Int32 SubsetMinY;
vtkm::Float32 FovX;
vtkm::Float32 FovY;
vtkm::Float32 FOV;
vtkm::Float32 Zoom;
bool IsViewDirty;
bool IsResDirty;
bool MortonSort;
bool LookAtSet;
//bool ImageSubsetModeOn;
vtkm::Vec<vtkm::Float32, 3> Look;
vtkm::Vec<vtkm::Float32, 3> Up;
@ -194,426 +68,110 @@ private:
vtkm::Matrix<vtkm::Float32, 4, 4> ViewProjectionMat;
public:
ColorBuffer4f FrameBuffer;
VTKM_CONT
Camera();
VTKM_CONT
Camera()
{
this->Height = 500;
this->Width = 500;
this->SubsetWidth = 500;
this->SubsetHeight = 500;
this->SubsetMinX = 0;
this->SubsetMinY = 0;
this->FovY = 30.f;
this->FovX = 30.f;
this->Zoom = 1.f;
this->Look[0] = 0.f;
this->Look[1] = 0.f;
this->Look[2] = -1.f;
this->LookAt[0] = 0.f;
this->LookAt[1] = 0.f;
this->LookAt[2] = -1.f;
this->Up[0] = 0.f;
this->Up[1] = 1.f;
this->Up[2] = 0.f;
this->Position[0] = 0.f;
this->Position[1] = 0.f;
this->Position[2] = 0.f;
this->IsViewDirty = true;
this->IsResDirty = true;
this->MortonSort = false;
this->FrameBuffer.Allocate(Height * Width);
//this->ImageSubsetModeOn = true;
}
~Camera();
// cuda does not compile if this is private
class PerspectiveRayGen;
std::string ToString();
VTKM_CONT
void SetParameters(const vtkm::rendering::Camera& camera,
const vtkm::rendering::CanvasRayTracer& canvas)
{
this->SetUp(camera.GetViewUp());
this->SetLookAt(camera.GetLookAt());
this->SetPosition(camera.GetPosition());
this->SetFieldOfView(camera.GetFieldOfView());
this->SetHeight(static_cast<vtkm::Int32>(canvas.GetHeight()));
this->SetWidth(static_cast<vtkm::Int32>(canvas.GetWidth()));
this->CameraView = camera;
}
vtkm::rendering::CanvasRayTracer& canvas);
VTKM_CONT
void SetHeight(const vtkm::Int32& height)
{
if (height <= 0)
{
throw vtkm::cont::ErrorBadValue("Camera height must be greater than zero.");
}
if (Height != height)
{
this->IsResDirty = true;
this->Height = height;
this->SetFieldOfView(this->FovX);
}
}
void SetHeight(const vtkm::Int32& height);
VTKM_CONT
vtkm::Int32 GetHeight() const { return this->Height; }
void WriteSettingsToLog();
VTKM_CONT
void SetWidth(const vtkm::Int32& width)
{
if (width <= 0)
{
throw vtkm::cont::ErrorBadValue("Camera width must be greater than zero.");
}
if (this->Width != width)
{
this->IsResDirty = true;
this->Width = width;
this->SetFieldOfView(this->FovX);
}
}
vtkm::Int32 GetHeight() const;
VTKM_CONT
vtkm::Int32 GetWidth() const { return this->Width; }
void SetWidth(const vtkm::Int32& width);
VTKM_CONT
void SetZoom(const vtkm::Float32& zoom)
{
if (zoom <= 0)
{
throw vtkm::cont::ErrorBadValue("Camera zoom must be greater than zero.");
}
if (this->Zoom != zoom)
{
this->IsViewDirty = true;
this->Zoom = zoom;
}
}
vtkm::Int32 GetWidth() const;
VTKM_CONT
vtkm::Float32 GetZoom() const { return this->Zoom; }
vtkm::Int32 GetSubsetWidth() const;
VTKM_CONT
void SetFieldOfView(const vtkm::Float32& degrees)
{
if (degrees <= 0)
{
throw vtkm::cont::ErrorBadValue("Camera feild of view must be greater than zero.");
}
if (degrees > 180)
{
throw vtkm::cont::ErrorBadValue("Camera feild of view must be less than 180.");
}
// fov is stored as a half angle
// float fovx= 2.f*atan(tan(view.view3d.fov/2.f)*view.w/view.h);
// fovx*=180.f/M_PI;
// camera->setFOVY((view.view3d.fov*(180.f/M_PI))/2.f);
// camera->setFOVX( fovx/2.f );
vtkm::Float32 newFOVY = (vtkm::Float32(this->Height) / vtkm::Float32(this->Width)) * degrees;
vtkm::Float32 newFOVX = degrees;
if (newFOVX != this->FovX)
{
this->IsViewDirty = true;
}
if (newFOVY != this->FovY)
{
this->IsViewDirty = true;
}
this->FovX = newFOVX;
this->FovY = newFOVY;
this->CameraView.SetFieldOfView(this->FovX);
}
vtkm::Int32 GetSubsetHeight() const;
VTKM_CONT
vtkm::Float32 GetFieldOfView() const { return this->FovX; }
void SetZoom(const vtkm::Float32& zoom);
VTKM_CONT
void SetUp(const vtkm::Vec<vtkm::Float32, 3>& up)
{
if (this->Up != up)
{
this->Up = up;
vtkm::Normalize(this->Up);
this->IsViewDirty = true;
}
}
vtkm::Float32 GetZoom() const;
VTKM_CONT
vtkm::Vec<vtkm::Float32, 3> GetUp() const { return this->Up; }
void SetFieldOfView(const vtkm::Float32& degrees);
VTKM_CONT
void SetLookAt(const vtkm::Vec<vtkm::Float32, 3>& lookAt)
{
if (this->LookAt != lookAt)
{
this->LookAt = lookAt;
this->IsViewDirty = true;
}
}
vtkm::Float32 GetFieldOfView() const;
VTKM_CONT
vtkm::Vec<vtkm::Float32, 3> GetLookAt() const { return this->LookAt; }
void SetUp(const vtkm::Vec<vtkm::Float32, 3>& up);
VTKM_CONT
void SetPosition(const vtkm::Vec<vtkm::Float32, 3>& position)
{
if (this->Position != position)
{
this->Position = position;
this->IsViewDirty = true;
}
}
void SetPosition(const vtkm::Vec<vtkm::Float32, 3>& position);
VTKM_CONT
vtkm::Vec<vtkm::Float32, 3> GetPosition() const { return this->Position; }
vtkm::Vec<vtkm::Float32, 3> GetPosition() const;
VTKM_CONT
void ResetIsViewDirty() { this->IsViewDirty = false; }
vtkm::Vec<vtkm::Float32, 3> GetUp() const;
VTKM_CONT
bool GetIsViewDirty() const { return this->IsViewDirty; }
void SetLookAt(const vtkm::Vec<vtkm::Float32, 3>& lookAt);
VTKM_CONT
void WriteToSurface(CanvasRayTracer* canvas,
const vtkm::cont::ArrayHandle<vtkm::Float32>& distances)
{
if (canvas == nullptr)
{
throw vtkm::cont::ErrorBadValue("Camera can not write to nullptr canvas");
}
if (this->Height != vtkm::Int32(canvas->GetHeight()) ||
this->Width != vtkm::Int32(canvas->GetWidth()))
{
throw vtkm::cont::ErrorBadValue("Camera: suface-view mismatched dims");
}
vtkm::worklet::DispatcherMapField<SurfaceConverter>(
SurfaceConverter(
this->Width,
this->SubsetWidth,
this->SubsetMinX,
this->SubsetMinY,
this->CameraView.CreateProjectionMatrix(canvas->GetWidth(), canvas->GetHeight()),
this->SubsetWidth * this->SubsetHeight))
.Invoke(
this->FrameBuffer,
distances,
vtkm::exec::ExecutionWholeArray<vtkm::Float32>(canvas->GetDepthBuffer()),
vtkm::exec::ExecutionWholeArray<vtkm::Vec<vtkm::Float32, 4>>(canvas->GetColorBuffer()));
//Force the transfer so the vectors contain data from device
canvas->GetColorBuffer().GetPortalControl().Get(0);
canvas->GetDepthBuffer().GetPortalControl().Get(0);
}
vtkm::Vec<vtkm::Float32, 3> GetLookAt() const;
VTKM_CONT
void CreateRays(Ray<DeviceAdapter>& rays, const vtkm::Bounds boundingBox = vtkm::Bounds())
{
this->UpdateDimensions(&rays, boundingBox);
//Set the origin of the ray back to the camera position
vtkm::worklet::DispatcherMapField<MemSet<vtkm::Float32>>(
MemSet<vtkm::Float32>(this->Position[0]))
.Invoke(rays.OriginX);
vtkm::worklet::DispatcherMapField<MemSet<vtkm::Float32>>(
MemSet<vtkm::Float32>(this->Position[1]))
.Invoke(rays.OriginY);
vtkm::worklet::DispatcherMapField<MemSet<vtkm::Float32>>(
MemSet<vtkm::Float32>(this->Position[2]))
.Invoke(rays.OriginZ);
//Reset the camera look vector
this->Look = this->LookAt - this->Position;
vtkm::Normalize(this->Look);
//Create the ray direction
vtkm::worklet::DispatcherMapField<PerspectiveRayGen>(PerspectiveRayGen(this->Width,
this->Height,
this->FovX,
this->FovY,
this->Look,
this->Up,
this->Zoom,
this->SubsetWidth,
this->SubsetMinX,
this->SubsetMinY))
.Invoke(rays.DirX,
rays.DirY,
rays.DirZ); //X Y Z
vtkm::worklet::DispatcherMapField<MemSet<vtkm::Float32>>(MemSet<vtkm::Float32>(1e12f))
.Invoke(rays.Distance);
//Reset the Rays Hit Index to -2
vtkm::worklet::DispatcherMapField<MemSet<vtkm::Id>>(MemSet<vtkm::Id>(-2)).Invoke(rays.HitIdx);
} //create rays
void ResetIsViewDirty();
VTKM_CONT
void CreateRays(VolumeRay<DeviceAdapter>& rays, const vtkm::Bounds& boundingBox = vtkm::Bounds())
{
bool GetIsViewDirty() const;
this->UpdateDimensions(&rays, boundingBox);
VTKM_CONT
void CreateRays(Ray<vtkm::Float32>& rays, const vtkm::cont::CoordinateSystem& coords);
VTKM_CONT
void CreateRays(Ray<vtkm::Float64>& rays, const vtkm::cont::CoordinateSystem& coords);
//Reset the camera look vector
this->Look = this->LookAt - this->Position;
vtkm::Normalize(this->Look);
//Create the ray direction
vtkm::worklet::DispatcherMapField<PerspectiveRayGen>(PerspectiveRayGen(this->Width,
this->Height,
this->FovX,
this->FovY,
this->Look,
this->Up,
this->Zoom,
this->SubsetWidth,
this->SubsetMinX,
this->SubsetMinY))
.Invoke(rays.DirX,
rays.DirY,
rays.DirZ); //X Y Z
VTKM_CONT
void GetPixelData(const vtkm::cont::CoordinateSystem& coords,
vtkm::Int32& activePixels,
vtkm::Float32& aveRayDistance);
} //create rays
template <typename Precision, typename DeviceAdapter>
VTKM_CONT void CreateRaysOnDevice(Ray<Precision>& rays,
DeviceAdapter,
const vtkm::Bounds boundingBox);
void CreateDebugRay(vtkm::Vec<vtkm::Int32, 2> pixel, Ray<vtkm::Float32>& rays);
void CreateDebugRay(vtkm::Vec<vtkm::Int32, 2> pixel, Ray<vtkm::Float64>& rays);
bool operator==(const Camera& other) const;
private:
template <typename Precision>
void CreateDebugRayImp(vtkm::Vec<vtkm::Int32, 2> pixel, Ray<Precision>& rays);
VTKM_CONT
void FindSubset(const vtkm::Bounds& bounds)
{
vtkm::Float32 x[2], y[2], z[2];
x[0] = static_cast<vtkm::Float32>(bounds.X.Min);
x[1] = static_cast<vtkm::Float32>(bounds.X.Max);
y[0] = static_cast<vtkm::Float32>(bounds.Y.Min);
y[1] = static_cast<vtkm::Float32>(bounds.Y.Max);
z[0] = static_cast<vtkm::Float32>(bounds.Z.Min);
z[1] = static_cast<vtkm::Float32>(bounds.Z.Max);
//Inise the data bounds
if (this->Position[0] >= x[0] && this->Position[0] <= x[1] && this->Position[1] >= y[0] &&
this->Position[1] <= y[1] && this->Position[2] >= z[0] && this->Position[2] <= z[1])
{
this->SubsetWidth = this->Width;
this->SubsetHeight = this->Height;
this->SubsetMinY = 0;
this->SubsetMinX = 0;
return;
}
void FindSubset(const vtkm::Bounds& bounds);
//std::cout<<"Bounds ("<<x[0]<<","<<y[0]<<","<<z[0]<<")-("<<x[1]<<","<<y[1]<<","<<z[1]<<std::endl;
vtkm::Float32 xmin, ymin, xmax, ymax, zmin, zmax;
xmin = vtkm::Infinity32();
ymin = vtkm::Infinity32();
zmin = vtkm::Infinity32();
xmax = vtkm::NegativeInfinity32();
ymax = vtkm::NegativeInfinity32();
zmax = vtkm::NegativeInfinity32();
vtkm::Vec<vtkm::Float32, 4> extentPoint;
for (vtkm::Int32 i = 0; i < 2; ++i)
for (vtkm::Int32 j = 0; j < 2; ++j)
for (vtkm::Int32 k = 0; k < 2; ++k)
{
extentPoint[0] = x[i];
extentPoint[1] = y[j];
extentPoint[2] = z[k];
extentPoint[3] = 1.f;
vtkm::Vec<vtkm::Float32, 4> transformed =
vtkm::MatrixMultiply(this->ViewProjectionMat, extentPoint);
// perform the perspective divide
for (vtkm::Int32 a = 0; a < 3; ++a)
{
transformed[a] = transformed[a] / transformed[3];
}
transformed[0] = (transformed[0] * 0.5f + 0.5f) * static_cast<vtkm::Float32>(Width);
transformed[1] = (transformed[1] * 0.5f + 0.5f) * static_cast<vtkm::Float32>(Height);
transformed[2] = (transformed[2] * 0.5f + 0.5f);
zmin = vtkm::Min(zmin, transformed[2]);
zmax = vtkm::Max(zmax, transformed[2]);
if (transformed[2] < 0 || transformed[2] > 1)
{
continue;
}
xmin = vtkm::Min(xmin, transformed[0]);
ymin = vtkm::Min(ymin, transformed[1]);
xmax = vtkm::Max(xmax, transformed[0]);
ymax = vtkm::Max(ymax, transformed[1]);
}
xmin -= .001f;
xmax += .001f;
ymin -= .001f;
ymax += .001f;
xmin = vtkm::Floor(vtkm::Min(vtkm::Max(0.f, xmin), vtkm::Float32(Width)));
xmax = vtkm::Ceil(vtkm::Min(vtkm::Max(0.f, xmax), vtkm::Float32(Width)));
ymin = vtkm::Floor(vtkm::Min(vtkm::Max(0.f, ymin), vtkm::Float32(Height)));
ymax = vtkm::Ceil(vtkm::Min(vtkm::Max(0.f, ymax), vtkm::Float32(Height)));
//printf("Pixel range = (%f,%f,%f), (%f,%f,%f)\n", xmin, ymin,zmin, xmax,ymax,zmax);
vtkm::Int32 dx = vtkm::Int32(xmax) - vtkm::Int32(xmin);
vtkm::Int32 dy = vtkm::Int32(ymax) - vtkm::Int32(ymin);
//
// scene is behind the camera
//
if (zmax < 0 || zmin > 1 || xmin >= xmax || ymin >= ymax)
{
this->SubsetWidth = 1;
this->SubsetHeight = 1;
this->SubsetMinX = 0;
this->SubsetMinY = 0;
}
else
{
this->SubsetWidth = dx;
this->SubsetHeight = dy;
this->SubsetMinX = vtkm::Int32(xmin);
this->SubsetMinY = vtkm::Int32(ymin);
}
}
VTKM_CONT
void UpdateDimensions(RayBase* rays, const vtkm::Bounds& boundingBox = vtkm::Bounds())
{
// If bounds have been provided, only cast rays that could hit the data
bool imageSubsetModeOn = boundingBox.IsNonEmpty();
//Update our ViewProjection matrix
this->ViewProjectionMat =
vtkm::MatrixMultiply(this->CameraView.CreateProjectionMatrix(this->Width, this->Height),
this->CameraView.CreateViewMatrix());
//Find the pixel footprint
if (imageSubsetModeOn)
{
this->FindSubset(boundingBox);
}
//Update the image dimensions
if (!imageSubsetModeOn)
{
this->SubsetWidth = this->Width;
this->SubsetHeight = this->Height;
this->SubsetMinY = 0;
this->SubsetMinX = 0;
}
else
{
if (this->SubsetWidth != this->Width)
{
this->IsResDirty = true;
}
if (this->SubsetHeight != this->Height)
{
this->IsResDirty = true;
}
}
// resize rays and buffers
if (this->IsResDirty)
{
rays->resize(this->SubsetHeight * this->SubsetWidth);
this->FrameBuffer.PrepareForOutput(this->SubsetHeight * this->SubsetWidth, DeviceAdapter());
}
this->IsResDirty = false;
}
template <typename DeviceAdapter, typename Precision>
VTKM_CONT void UpdateDimensions(Ray<Precision>& rays,
DeviceAdapter,
const vtkm::Bounds& boundingBox);
}; // class camera
}

@ -0,0 +1,468 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_rendering_raytracing_Cell_Intersector_h
#define vtk_m_rendering_raytracing_Cell_Intersector_h
#include <vtkm/rendering/raytracing/CellTables.h>
#include <vtkm/rendering/raytracing/TriangleIntersector.h>
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
//
// Any supported element. If the cell shape is not
// supported it does nothing, e.g. a 2D cellkk.
//
template <typename T>
VTKM_EXEC_CONT inline void IntersectZoo(T xpoints[8],
T ypoints[8],
T zpoints[8],
const vtkm::Vec<T, 3>& dir,
const vtkm::Vec<T, 3>& origin,
T distances[6],
const vtkm::Int32& shapeType)
{
// Some precalc for water tight intersections
T sx, sy, sz;
vtkm::Int32 kx, ky, kz;
WaterTight<T> intersector;
intersector.FindDir(dir, sx, sy, sz, kx, ky, kz);
const vtkm::Int32 tableOffset = ZooLookUp[CellTypeLookUp[shapeType]][0];
const vtkm::Int32 numTriangles = ZooLookUp[CellTypeLookUp[shapeType]][1];
// Decompose each face into two triangles
for (int i = 0; i < 6; ++i)
distances[i] = -1.;
for (int i = 0; i < numTriangles; ++i)
{
const vtkm::Int32 offset = tableOffset + i;
vtkm::Vec<T, 3> a, c, b;
a[0] = xpoints[ZooTable[offset][1]];
a[1] = ypoints[ZooTable[offset][1]];
a[2] = zpoints[ZooTable[offset][1]];
b[0] = xpoints[ZooTable[offset][2]];
b[1] = ypoints[ZooTable[offset][2]];
b[2] = zpoints[ZooTable[offset][2]];
c[0] = xpoints[ZooTable[offset][3]];
c[1] = ypoints[ZooTable[offset][3]];
c[2] = zpoints[ZooTable[offset][3]];
const vtkm::Int32 faceId = ZooTable[offset][0];
T distance = -1.f;
T uNotUsed, vNotUsed;
intersector.IntersectTriSn(a,
b,
c,
sx,
sy,
sz,
kx,
ky,
kz,
distance,
uNotUsed,
vNotUsed,
origin[0],
origin[1],
origin[2]);
if (distance != -1.f)
{
if (distances[faceId] != -1.f)
distances[faceId] = vtkm::Min(distance, distances[faceId]);
else
distances[faceId] = distance;
}
}
}
template <typename T>
VTKM_EXEC_CONT inline void IntersectHex(T xpoints[8],
T ypoints[8],
T zpoints[8],
const vtkm::Vec<T, 3>& dir,
const vtkm::Vec<T, 3>& origin,
T distances[6])
{
// Some precalc for water tight intersections
T sx, sy, sz;
vtkm::Int32 kx, ky, kz;
WaterTight<T> intersector;
intersector.FindDir(dir, sx, sy, sz, kx, ky, kz);
// Decompose each face into two triangles
for (int i = 0; i < 6; ++i)
{
vtkm::Vec<T, 3> a, c, b, d;
a[0] = xpoints[ShapesFaceList[i][1]];
a[1] = ypoints[ShapesFaceList[i][1]];
a[2] = zpoints[ShapesFaceList[i][1]];
b[0] = xpoints[ShapesFaceList[i][2]];
b[1] = ypoints[ShapesFaceList[i][2]];
b[2] = zpoints[ShapesFaceList[i][2]];
c[0] = xpoints[ShapesFaceList[i][3]];
c[1] = ypoints[ShapesFaceList[i][3]];
c[2] = zpoints[ShapesFaceList[i][3]];
d[0] = xpoints[ShapesFaceList[i][4]];
d[1] = ypoints[ShapesFaceList[i][4]];
d[2] = zpoints[ShapesFaceList[i][4]];
T distance = -1.f;
distances[i] = distance; //init to -1
T uNotUsed, vNotUsed;
intersector.IntersectTriSn(a,
b,
c,
sx,
sy,
sz,
kx,
ky,
kz,
distance,
uNotUsed,
vNotUsed,
origin[0],
origin[1],
origin[2]);
if (distance != -1.f)
distances[i] = distance;
distance = -1.f;
intersector.IntersectTriSn(a,
c,
d,
sx,
sy,
sz,
kx,
ky,
kz,
distance,
uNotUsed,
vNotUsed,
origin[0],
origin[1],
origin[2]);
if (distance != -1.f)
{
if (distances[i] != -1.f)
distances[i] = vtkm::Min(distance, distances[i]);
else
distances[i] = distance;
}
}
}
template <typename T>
VTKM_EXEC_CONT inline void IntersectTet(T xpoints[8],
T ypoints[8],
T zpoints[8],
const vtkm::Vec<T, 3>& dir,
const vtkm::Vec<T, 3>& origin,
T distances[6])
{
// Some precalc for water tight intersections
T sx, sy, sz;
vtkm::Int32 kx, ky, kz;
WaterTight<T> intersector;
intersector.FindDir(dir, sx, sy, sz, kx, ky, kz);
const vtkm::Int32 tableOffset = FaceLookUp[CellTypeLookUp[CELL_SHAPE_TETRA]][0];
for (vtkm::Int32 i = 0; i < 4; ++i)
{
vtkm::Vec<T, 3> a, c, b;
a[0] = xpoints[ShapesFaceList[i + tableOffset][1]];
a[1] = ypoints[ShapesFaceList[i + tableOffset][1]];
a[2] = zpoints[ShapesFaceList[i + tableOffset][1]];
b[0] = xpoints[ShapesFaceList[i + tableOffset][2]];
b[1] = ypoints[ShapesFaceList[i + tableOffset][2]];
b[2] = zpoints[ShapesFaceList[i + tableOffset][2]];
c[0] = xpoints[ShapesFaceList[i + tableOffset][3]];
c[1] = ypoints[ShapesFaceList[i + tableOffset][3]];
c[2] = zpoints[ShapesFaceList[i + tableOffset][3]];
T distance = -1.f;
distances[i] = distance; //init to -1
T uNotUsed, vNotUsed;
intersector.IntersectTriSn(a,
b,
c,
sx,
sy,
sz,
kx,
ky,
kz,
distance,
uNotUsed,
vNotUsed,
origin[0],
origin[1],
origin[2]);
if (distance != -1.f)
distances[i] = distance;
}
}
//
// Wedge
//
template <typename T>
VTKM_EXEC_CONT inline void IntersectWedge(T xpoints[8],
T ypoints[8],
T zpoints[8],
const vtkm::Vec<T, 3>& dir,
const vtkm::Vec<T, 3>& origin,
T distances[6])
{
// Some precalc for water tight intersections
T sx, sy, sz;
vtkm::Int32 kx, ky, kz;
WaterTight<T> intersector;
intersector.FindDir(dir, sx, sy, sz, kx, ky, kz);
// TODO: try two sepate loops to see performance impact
const vtkm::Int32 tableOffset = FaceLookUp[CellTypeLookUp[CELL_SHAPE_WEDGE]][0];
// Decompose each face into two triangles
for (int i = 0; i < 5; ++i)
{
vtkm::Vec<T, 3> a, c, b, d;
a[0] = xpoints[ShapesFaceList[i + tableOffset][1]];
a[1] = ypoints[ShapesFaceList[i + tableOffset][1]];
a[2] = zpoints[ShapesFaceList[i + tableOffset][1]];
b[0] = xpoints[ShapesFaceList[i + tableOffset][2]];
b[1] = ypoints[ShapesFaceList[i + tableOffset][2]];
b[2] = zpoints[ShapesFaceList[i + tableOffset][2]];
c[0] = xpoints[ShapesFaceList[i + tableOffset][3]];
c[1] = ypoints[ShapesFaceList[i + tableOffset][3]];
c[2] = zpoints[ShapesFaceList[i + tableOffset][3]];
d[0] = xpoints[ShapesFaceList[i + tableOffset][4]];
d[1] = ypoints[ShapesFaceList[i + tableOffset][4]];
d[2] = zpoints[ShapesFaceList[i + tableOffset][4]];
T distance = -1.f;
distances[i] = distance; //init to -1
T uNotUsed, vNotUsed;
intersector.IntersectTriSn(a,
b,
c,
sx,
sy,
sz,
kx,
ky,
kz,
distance,
uNotUsed,
vNotUsed,
origin[0],
origin[1],
origin[2]);
if (distance != -1.f)
distances[i] = distance;
//
//First two faces are triangles
//
if (i < 2)
continue;
distance = -1.f;
intersector.IntersectTriSn(a,
c,
d,
sx,
sy,
sz,
kx,
ky,
kz,
distance,
uNotUsed,
vNotUsed,
origin[0],
origin[1],
origin[2]);
if (distance != -1.f)
{
if (distances[i] != -1.f)
distances[i] = vtkm::Min(distance, distances[i]);
else
distances[i] = distance;
}
}
}
//
// General Template should never be instantiated
//
template <int CellType>
class CellIntersector
{
public:
template <typename T>
VTKM_EXEC_CONT inline void IntersectCell(T* vtkmNotUsed(xpoints),
T* vtkmNotUsed(ypoints),
T* vtkmNotUsed(zpoints),
const vtkm::Vec<T, 3>& vtkmNotUsed(dir),
const vtkm::Vec<T, 3>& vtkmNotUsed(origin),
T* vtkmNotUsed(distances),
const vtkm::UInt8 vtkmNotUsed(cellShape = 12));
};
//
// Hex Specialization
//
template <>
class CellIntersector<CELL_SHAPE_HEXAHEDRON>
{
public:
template <typename T>
VTKM_EXEC_CONT inline void IntersectCell(T* xpoints,
T* ypoints,
T* zpoints,
const vtkm::Vec<T, 3>& dir,
const vtkm::Vec<T, 3>& origin,
T* distances,
const vtkm::UInt8 cellShape = 12) const
{
if (cellShape == 12)
{
IntersectZoo(xpoints, ypoints, zpoints, dir, origin, distances, cellShape);
}
else
{
printf("CellIntersector Hex Error: unsupported cell type. Doing nothing\n");
}
}
};
//
//
// Hex Specialization Structured
//
template <>
class CellIntersector<254>
{
public:
template <typename T>
VTKM_EXEC_CONT inline void IntersectCell(T* xpoints,
T* ypoints,
T* zpoints,
const vtkm::Vec<T, 3>& dir,
const vtkm::Vec<T, 3>& origin,
T* distances,
const vtkm::UInt8 cellShape = 12) const
{
if (cellShape == 12)
{
IntersectZoo(xpoints, ypoints, zpoints, dir, origin, distances, cellShape);
}
else
{
printf("CellIntersector Hex Error: unsupported cell type. Doing nothing\n");
}
}
};
//
// Tet Specialization
//
template <>
class CellIntersector<CELL_SHAPE_TETRA>
{
public:
template <typename T>
VTKM_EXEC_CONT inline void IntersectCell(T* xpoints,
T* ypoints,
T* zpoints,
const vtkm::Vec<T, 3>& dir,
const vtkm::Vec<T, 3>& origin,
T distances[6],
const vtkm::UInt8 cellShape = 12) const
{
if (cellShape == CELL_SHAPE_TETRA)
{
IntersectTet(xpoints, ypoints, zpoints, dir, origin, distances);
}
else
{
printf("CellIntersector Tet Error: unsupported cell type. Doing nothing\n");
}
}
};
//
// Wedge Specialization
//
template <>
class CellIntersector<CELL_SHAPE_WEDGE>
{
public:
template <typename T>
VTKM_EXEC_CONT inline void IntersectCell(T* xpoints,
T* ypoints,
T* zpoints,
const vtkm::Vec<T, 3>& dir,
const vtkm::Vec<T, 3>& origin,
T distances[6],
const vtkm::UInt8 cellShape = 12) const
{
if (cellShape == CELL_SHAPE_WEDGE)
{
IntersectWedge(xpoints, ypoints, zpoints, dir, origin, distances);
}
else
{
printf("CellIntersector Wedge Error: unsupported cell type. Doing nothing\n");
}
}
};
//
// Zoo elements
//
template <>
class CellIntersector<255>
{
public:
template <typename T>
VTKM_EXEC_CONT inline void IntersectCell(T* xpoints,
T* ypoints,
T* zpoints,
const vtkm::Vec<T, 3>& dir,
const vtkm::Vec<T, 3>& origin,
T distances[6],
const vtkm::UInt8 cellShape = 0) const
{
IntersectZoo(xpoints, ypoints, zpoints, dir, origin, distances, cellShape);
}
};
}
}
} // namespace vtkm::rendering::raytracing
#endif

@ -0,0 +1,317 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_rendering_raytracing_CellSampler_h
#define vtk_m_rendering_raytracing_CellSampler_h
#include <vtkm/VecVariable.h>
#include <vtkm/exec/CellInterpolate.h>
#include <vtkm/exec/ParametricCoordinates.h>
#ifndef CELL_SHAPE_ZOO
#define CELL_SHAPE_ZOO 255
#endif
#ifndef CELL_SHAPE_STRUCTURED
#define CELL_SHAPE_STRUCTURED 254
#endif
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
namespace detail
{
template <typename CellTag>
VTKM_EXEC_CONT inline vtkm::Int32 GetNumberOfPoints(CellTag tag);
template <>
VTKM_EXEC_CONT inline vtkm::Int32 GetNumberOfPoints<vtkm::CellShapeTagHexahedron>(
vtkm::CellShapeTagHexahedron vtkmNotUsed(tag))
{
return 8;
}
template <>
VTKM_EXEC_CONT inline vtkm::Int32 GetNumberOfPoints<vtkm::CellShapeTagTetra>(
vtkm::CellShapeTagTetra vtkmNotUsed(tag))
{
return 4;
}
template <>
VTKM_EXEC_CONT inline vtkm::Int32 GetNumberOfPoints<vtkm::CellShapeTagWedge>(
vtkm::CellShapeTagWedge vtkmNotUsed(tag))
{
return 6;
}
template <>
VTKM_EXEC_CONT inline vtkm::Int32 GetNumberOfPoints<vtkm::CellShapeTagPyramid>(
vtkm::CellShapeTagPyramid vtkmNotUsed(tag))
{
return 5;
}
template <typename P, typename S, typename WorkletType, typename CellShapeTagType>
VTKM_EXEC_CONT inline bool Sample(const vtkm::Vec<vtkm::Vec<P, 3>, 8>& points,
const vtkm::Vec<S, 8>& scalars,
const vtkm::Vec<P, 3>& sampleLocation,
S& lerpedScalar,
const WorkletType& callingWorklet,
const CellShapeTagType& shapeTag)
{
bool validSample = true;
vtkm::VecVariable<vtkm::Vec<P, 3>, 8> pointsVec;
vtkm::VecVariable<S, 8> scalarVec;
for (vtkm::Int32 i = 0; i < GetNumberOfPoints(shapeTag); ++i)
{
pointsVec.Append(points[i]);
scalarVec.Append(scalars[i]);
}
vtkm::Vec<P, 3> pcoords = vtkm::exec::WorldCoordinatesToParametricCoordinates(
pointsVec, sampleLocation, shapeTag, callingWorklet);
P pmin, pmax;
pmin = vtkm::Min(vtkm::Min(pcoords[0], pcoords[1]), pcoords[2]);
pmax = vtkm::Max(vtkm::Max(pcoords[0], pcoords[1]), pcoords[2]);
if (pmin < 0.f || pmax > 1.f)
{
validSample = false;
}
lerpedScalar = vtkm::exec::CellInterpolate(scalarVec, pcoords, shapeTag, callingWorklet);
return validSample;
}
template <typename S, typename P, typename WorkletType, typename CellShapeTagType>
VTKM_EXEC_CONT inline bool Sample(const vtkm::VecRectilinearPointCoordinates<3>& points,
const vtkm::Vec<S, 8>& scalars,
const vtkm::Vec<P, 3>& sampleLocation,
S& lerpedScalar,
const WorkletType& callingWorklet,
const CellShapeTagType& vtkmNotUsed(shapeTag))
{
bool validSample = true;
vtkm::Vec<P, 3> pcoords = vtkm::exec::WorldCoordinatesToParametricCoordinates(
points, sampleLocation, vtkm::CellShapeTagHexahedron(), callingWorklet);
P pmin, pmax;
pmin = vtkm::Min(vtkm::Min(pcoords[0], pcoords[1]), pcoords[2]);
pmax = vtkm::Max(vtkm::Max(pcoords[0], pcoords[1]), pcoords[2]);
if (pmin < 0.f || pmax > 1.f)
{
validSample = false;
}
lerpedScalar =
vtkm::exec::CellInterpolate(scalars, pcoords, vtkm::CellShapeTagHexahedron(), callingWorklet);
return validSample;
}
} // namespace detail
//
// General Template: returns false if sample location is outside the cell
//
template <int CellType>
class CellSampler
{
public:
template <typename P, typename S, typename WorkletType>
VTKM_EXEC_CONT inline bool SampleCell(const vtkm::Vec<vtkm::Vec<P, 3>, 8>& vtkmNotUsed(points),
const vtkm::Vec<S, 8>& vtkmNotUsed(scalars),
const vtkm::Vec<P, 3>& vtkmNotUsed(sampleLocation),
S& vtkmNotUsed(lerpedScalar),
const WorkletType& vtkmNotUsed(callingWorklet),
const vtkm::Int32& vtkmNotUsed(cellShape = CellType)) const
{
static_assert(CellType != CELL_SHAPE_ZOO && CellType != CELL_SHAPE_STRUCTURED &&
CellType != CELL_SHAPE_HEXAHEDRON && CellType != CELL_SHAPE_TETRA &&
CellType != CELL_SHAPE_WEDGE && CellType != CELL_SHAPE_PYRAMID,
"Cell Sampler: Default template. This should not happen.\n");
return false;
}
};
//
// Zoo Sampler
//
template <>
class CellSampler<255>
{
public:
template <typename P, typename S, typename WorkletType>
VTKM_EXEC_CONT inline bool SampleCell(const vtkm::Vec<vtkm::Vec<P, 3>, 8>& points,
const vtkm::Vec<S, 8>& scalars,
const vtkm::Vec<P, 3>& sampleLocation,
S& lerpedScalar,
const WorkletType& callingWorklet,
const vtkm::Int32& cellShape) const
{
bool valid = false;
if (cellShape == CELL_SHAPE_HEXAHEDRON)
{
valid = detail::Sample(points,
scalars,
sampleLocation,
lerpedScalar,
callingWorklet,
vtkm::CellShapeTagHexahedron());
}
if (cellShape == CELL_SHAPE_TETRA)
{
valid = detail::Sample(
points, scalars, sampleLocation, lerpedScalar, callingWorklet, vtkm::CellShapeTagTetra());
}
if (cellShape == CELL_SHAPE_WEDGE)
{
valid = detail::Sample(
points, scalars, sampleLocation, lerpedScalar, callingWorklet, vtkm::CellShapeTagWedge());
}
if (cellShape == CELL_SHAPE_PYRAMID)
{
valid = detail::Sample(
points, scalars, sampleLocation, lerpedScalar, callingWorklet, vtkm::CellShapeTagPyramid());
}
return valid;
}
};
//
// Single type hex
//
template <>
class CellSampler<CELL_SHAPE_HEXAHEDRON>
{
public:
template <typename P, typename S, typename WorkletType>
VTKM_EXEC_CONT inline bool SampleCell(
const vtkm::Vec<vtkm::Vec<P, 3>, 8>& points,
const vtkm::Vec<S, 8>& scalars,
const vtkm::Vec<P, 3>& sampleLocation,
S& lerpedScalar,
const WorkletType& callingWorklet,
const vtkm::Int32& vtkmNotUsed(cellShape = CELL_SHAPE_HEXAHEDRON)) const
{
return detail::Sample(points,
scalars,
sampleLocation,
lerpedScalar,
callingWorklet,
vtkm::CellShapeTagHexahedron());
}
};
//
// Single type hex uniform and rectilinear
// calls fast path for sampling
//
template <>
class CellSampler<CELL_SHAPE_STRUCTURED>
{
public:
template <typename P, typename S, typename WorkletType>
VTKM_EXEC_CONT inline bool SampleCell(
const vtkm::Vec<vtkm::Vec<P, 3>, 8>& points,
const vtkm::Vec<S, 8>& scalars,
const vtkm::Vec<P, 3>& sampleLocation,
S& lerpedScalar,
const WorkletType& callingWorklet,
const vtkm::Int32& vtkmNotUsed(cellShape = CELL_SHAPE_HEXAHEDRON)) const
{
vtkm::VecRectilinearPointCoordinates<3> rPoints(points[0], points[6] - points[0]);
return detail::Sample(rPoints,
scalars,
sampleLocation,
lerpedScalar,
callingWorklet,
vtkm::CellShapeTagHexahedron());
}
};
//
// Single type pyramid
//
template <>
class CellSampler<CELL_SHAPE_PYRAMID>
{
public:
template <typename P, typename S, typename WorkletType>
VTKM_EXEC_CONT inline bool SampleCell(
const vtkm::Vec<vtkm::Vec<P, 3>, 8>& points,
const vtkm::Vec<S, 8>& scalars,
const vtkm::Vec<P, 3>& sampleLocation,
S& lerpedScalar,
const WorkletType& callingWorklet,
const vtkm::Int32& vtkmNotUsed(cellShape = CELL_SHAPE_PYRAMID)) const
{
return detail::Sample(
points, scalars, sampleLocation, lerpedScalar, callingWorklet, vtkm::CellShapeTagPyramid());
}
};
//
// Single type Tet
//
template <>
class CellSampler<CELL_SHAPE_TETRA>
{
public:
template <typename P, typename S, typename WorkletType>
VTKM_EXEC_CONT inline bool SampleCell(
const vtkm::Vec<vtkm::Vec<P, 3>, 8>& points,
const vtkm::Vec<S, 8>& scalars,
const vtkm::Vec<P, 3>& sampleLocation,
S& lerpedScalar,
const WorkletType& callingWorklet,
const vtkm::Int32& vtkmNotUsed(cellShape = CELL_SHAPE_TETRA)) const
{
return detail::Sample(
points, scalars, sampleLocation, lerpedScalar, callingWorklet, vtkm::CellShapeTagTetra());
}
};
//
// Single type Wedge
//
template <>
class CellSampler<CELL_SHAPE_WEDGE>
{
public:
template <typename P, typename S, typename WorkletType>
VTKM_EXEC_CONT inline bool SampleCell(
const vtkm::Vec<vtkm::Vec<P, 3>, 8>& points,
const vtkm::Vec<S, 8>& scalars,
const vtkm::Vec<P, 3>& sampleLocation,
S& lerpedScalar,
const WorkletType& callingWorklet,
const vtkm::Int32& vtkmNotUsed(cellShape = CELL_SHAPE_WEDGE)) const
{
return detail::Sample(
points, scalars, sampleLocation, lerpedScalar, callingWorklet, vtkm::CellShapeTagWedge());
}
};
}
}
} // namespace vtkm::rendering::raytracing
#endif

@ -0,0 +1,132 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_rendering_raytracing_CellTables_h
#define vtk_m_rendering_raytracing_CellTables_h
#include <vtkm/Types.h>
#include <vtkm/internal/ExportMacros.h>
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
//LookUp of Shapes to FaceLookUp
VTKM_EXEC_CONSTANT
static vtkm::Int32 CellTypeLookUp[15] = {
4, // 0 Nothing
4, // 1 Vertex
4, // 2 (Not Used) Poly Vertex
4, // 3 Line
4, // 4 (Not Used) Poly Line
4, // 5 Triangle
4, // 6 (not used) triangle strip
4, // 7 Polygon
4, // 8 (Not used)Pixel
4, // 9 Quad
1, // 10 Tetra
4, // 11 (Not used) Voxel
0, // 12 Hex
2, // 13 Wedge
3 // 14 Pyramid
};
VTKM_EXEC_CONSTANT
static vtkm::Int32 FaceLookUp[5][3] = {
{ 0, 6, 8 }, //hex offset into shapes face list, num faces and number of Indices
{ 6, 4, 4 }, //tet
{ 10, 5, 6 }, //wedge
{ 15, 5, 5 }, //pyramid
{ -1, 0, 0 } //unsupported shape
};
// The convention for the faces is that looking from the outside of
// the shape at a face, triangles should wind CCW.
// Quads are broken up by {4=quad,a,b,c,d}:
// t1 = abc and t2 = acd. Indices of the face are ordered CW, and the mapping
// of t1 and t2 become CCW.
// Since we know the triangle winding, we could tell
// if we hit an inside face or outside face.
VTKM_EXEC_CONSTANT
static vtkm::Int32 ShapesFaceList[20][5] = {
//hex
{ 4, 0, 1, 5, 4 }, //face 0
{ 4, 1, 2, 6, 5 },
{ 4, 3, 7, 6, 2 },
{ 4, 0, 4, 7, 3 },
{ 4, 0, 3, 2, 1 },
{ 4, 4, 5, 6, 7 }, //face 5
//tet
{ 3, 0, 3, 1, -1 },
{ 3, 1, 2, 3, -1 },
{ 3, 0, 2, 3, -1 },
{ 3, 0, 2, 1, -1 },
//wedge
{ 3, 0, 1, 2, -1 },
{ 3, 3, 5, 4, -1 },
{ 4, 3, 0, 2, 5 },
{ 4, 1, 4, 5, 2 },
{ 4, 0, 3, 4, 1 },
//pyramid
{ 3, 0, 4, 1, -1 },
{ 3, 1, 2, 4, -1 },
{ 3, 2, 3, 4, -1 },
{ 3, 0, 4, 3, -1 },
{ 4, 3, 2, 1, 0 }
};
// Test of zoo table.
// Format (faceNumber, triangle)
//
VTKM_EXEC_CONSTANT
static vtkm::Int32 ZooTable[30][4] = {
{ 0, 0, 1, 5 }, // hex
{ 0, 0, 5, 4 }, { 1, 1, 2, 6 }, { 1, 1, 6, 5 }, { 2, 3, 7, 6 }, { 2, 3, 6, 2 },
{ 3, 0, 4, 7 }, { 3, 0, 7, 3 }, { 4, 0, 3, 2 }, { 4, 0, 2, 1 }, { 5, 4, 5, 6 },
{ 5, 4, 6, 7 }, { 0, 0, 3, 1 }, // Tet
{ 1, 1, 2, 3 }, { 2, 0, 2, 3 }, { 3, 0, 2, 1 }, { 0, 0, 1, 2 }, // Wedge
{ 1, 3, 5, 4 }, { 2, 3, 0, 2 }, { 2, 3, 2, 5 }, { 3, 1, 4, 5 }, { 3, 1, 5, 2 },
{ 4, 0, 3, 4 }, { 4, 0, 4, 1 }, { 0, 0, 4, 1 }, // Pyramid
{ 1, 1, 2, 4 }, { 2, 2, 3, 4 }, { 3, 0, 4, 3 }, { 4, 3, 2, 1 }, { 4, 3, 1, 0 }
};
//
// Offset into zoo table and the
// number of triangles for the shape
//
VTKM_EXEC_CONSTANT
static vtkm::Int32 ZooLookUp[5][2] = {
{ 0, 12 }, //hex offset into shapes face list, num faces and number of Indices
{ 12, 4 }, //tet
{ 16, 8 }, //wedge
{ 24, 6 }, //pyramid
{ -1, 0 } //unsupported shape
};
} // namespace raytracing
} // namespace rendering
} // namespace vtkm
#endif

@ -0,0 +1,466 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <vtkm/cont/TryExecute.h>
#include <vtkm/rendering/raytracing/ChannelBuffer.h>
#include <vtkm/rendering/raytracing/ChannelBufferOperations.h>
#include <vtkm/rendering/raytracing/RayTracingTypeDefs.h>
#include <vtkm/rendering/vtkm_rendering_export.h>
#include <vtkm/worklet/DispatcherMapField.h>
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
template <typename Precision>
ChannelBuffer<Precision>::ChannelBuffer()
{
this->NumChannels = 4;
this->Size = 0;
this->Name = "default";
}
template <typename Precision>
ChannelBuffer<Precision>::ChannelBuffer(const vtkm::Int32 numChannels, const vtkm::Id size)
{
if (size < 1)
throw vtkm::cont::ErrorBadValue("ChannelBuffer: Size must be greater that 0");
if (numChannels < 1)
throw vtkm::cont::ErrorBadValue("ChannelBuffer: NumChannels must be greater that 0");
this->NumChannels = numChannels;
this->Size = size;
Buffer.Allocate(this->Size * this->NumChannels);
}
template <typename Precision>
vtkm::Int32 ChannelBuffer<Precision>::GetNumChannels() const
{
return this->NumChannels;
}
template <typename Precision>
vtkm::Id ChannelBuffer<Precision>::GetSize() const
{
return this->Size;
}
template <typename Precision>
vtkm::Id ChannelBuffer<Precision>::GetBufferLength() const
{
return this->Size * static_cast<vtkm::Id>(this->NumChannels);
}
template <typename Precision>
void ChannelBuffer<Precision>::SetName(const std::string name)
{
this->Name = name;
}
template <typename Precision>
std::string ChannelBuffer<Precision>::GetName() const
{
return this->Name;
}
template <typename Precision>
void ChannelBuffer<Precision>::Resize(const vtkm::Id newSize)
{
if (newSize < 0)
throw vtkm::cont::ErrorBadValue("ChannelBuffer resize: Size must be greater than -1");
this->Size = newSize;
this->Buffer.Allocate(this->Size * static_cast<vtkm::Id>(NumChannels));
}
class ExtractChannel : public vtkm::worklet::WorkletMapField
{
protected:
vtkm::Id NumChannels; // the nnumber of channels in the buffer
vtkm::Id ChannelNum; // the channel to extract
public:
VTKM_CONT
ExtractChannel(const vtkm::Int32 numChannels, const vtkm::Int32 channel)
: NumChannels(numChannels)
, ChannelNum(channel)
{
}
typedef void ControlSignature(FieldOut<>, WholeArrayIn<>);
typedef void ExecutionSignature(_1, _2, WorkIndex);
template <typename T, typename BufferPortalType>
VTKM_EXEC void operator()(T& outValue,
const BufferPortalType& inBuffer,
const vtkm::Id& index) const
{
vtkm::Id valueIndex = index * NumChannels + ChannelNum;
BOUNDS_CHECK(inBuffer, valueIndex);
outValue = inBuffer.Get(valueIndex);
}
}; //class Extract Channel
template <typename Precision>
struct ExtractChannelFunctor
{
ChannelBuffer<Precision>* Self;
vtkm::cont::ArrayHandle<Precision> Output;
vtkm::Int32 Channel;
ExtractChannelFunctor(ChannelBuffer<Precision>* self,
vtkm::cont::ArrayHandle<Precision> output,
const vtkm::Int32 channel)
: Self(self)
, Output(output)
, Channel(channel)
{
}
template <typename Device>
bool operator()(Device device)
{
Output.PrepareForOutput(Self->GetSize(), device);
vtkm::worklet::DispatcherMapField<ExtractChannel, Device>(
ExtractChannel(Self->GetNumChannels(), Channel))
.Invoke(Output, Self->Buffer);
return true;
}
};
template <typename Precision>
ChannelBuffer<Precision> ChannelBuffer<Precision>::GetChannel(const vtkm::Int32 channel)
{
if (channel < 0 || channel >= this->NumChannels)
throw vtkm::cont::ErrorBadValue("ChannelBuffer: invalid channel to extract");
ChannelBuffer<Precision> output(1, this->Size);
output.SetName(this->Name);
ExtractChannelFunctor<Precision> functor(this, output.Buffer, channel);
vtkm::cont::TryExecute(functor);
return output;
}
//static
class Expand : public vtkm::worklet::WorkletMapField
{
protected:
vtkm::Int32 NumChannels;
public:
VTKM_CONT
Expand(const vtkm::Int32 numChannels)
: NumChannels(numChannels)
{
}
typedef void ControlSignature(FieldIn<>, WholeArrayIn<>, WholeArrayOut<>);
typedef void ExecutionSignature(_1, _2, _3, WorkIndex);
template <typename T, typename IndexPortalType, typename BufferPortalType>
VTKM_EXEC void operator()(const T& inValue,
const IndexPortalType& sparseIndexes,
BufferPortalType& outBuffer,
const vtkm::Id& index) const
{
vtkm::Id sparse = index / NumChannels;
BOUNDS_CHECK(sparseIndexes, sparse);
vtkm::Id sparseIndex = sparseIndexes.Get(sparse) * NumChannels;
vtkm::Id outIndex = sparseIndex + index % NumChannels;
BOUNDS_CHECK(outBuffer, outIndex);
outBuffer.Set(outIndex, inValue);
}
}; //class Expand
template <typename Precision>
struct ExpandFunctorSignature
{
vtkm::cont::ArrayHandle<Precision> Input;
vtkm::cont::ArrayHandle<vtkm::Id> SparseIndexes;
ChannelBuffer<Precision>* Output;
vtkm::cont::ArrayHandle<Precision> Signature;
vtkm::Id OutputLength;
vtkm::Int32 NumChannels;
ExpandFunctorSignature(vtkm::cont::ArrayHandle<Precision> input,
vtkm::cont::ArrayHandle<vtkm::Id> sparseIndexes,
ChannelBuffer<Precision>* outChannelBuffer,
vtkm::Id outputLength,
vtkm::Int32 numChannels,
vtkm::cont::ArrayHandle<Precision> signature)
: Input(input)
, SparseIndexes(sparseIndexes)
, Output(outChannelBuffer)
, Signature(signature)
, OutputLength(outputLength)
, NumChannels(numChannels)
{
}
template <typename Device>
bool operator()(Device device)
{
vtkm::Id totalSize = OutputLength * static_cast<vtkm::Id>(NumChannels);
Output->Buffer.PrepareForOutput(totalSize, device);
ChannelBufferOperations::InitChannels(*Output, Signature, device);
vtkm::worklet::DispatcherMapField<Expand, Device>(Expand(NumChannels))
.Invoke(Input, SparseIndexes, Output->Buffer);
return true;
}
};
template <typename Precision>
struct ExpandFunctor
{
vtkm::cont::ArrayHandle<Precision> Input;
vtkm::cont::ArrayHandle<vtkm::Id> SparseIndexes;
ChannelBuffer<Precision>* Output;
vtkm::Id OutputLength;
vtkm::Int32 NumChannels;
Precision InitVal;
ExpandFunctor(vtkm::cont::ArrayHandle<Precision> input,
vtkm::cont::ArrayHandle<vtkm::Id> sparseIndexes,
ChannelBuffer<Precision>* outChannelBuffer,
vtkm::Id outputLength,
vtkm::Int32 numChannels,
Precision initVal)
: Input(input)
, SparseIndexes(sparseIndexes)
, Output(outChannelBuffer)
, OutputLength(outputLength)
, NumChannels(numChannels)
, InitVal(initVal)
{
}
template <typename Device>
bool operator()(Device device)
{
vtkm::Id totalSize = OutputLength * static_cast<vtkm::Id>(NumChannels);
Output->Buffer.PrepareForOutput(totalSize, device);
ChannelBufferOperations::InitConst(*Output, InitVal, device);
vtkm::worklet::DispatcherMapField<Expand, Device>(Expand(NumChannels))
.Invoke(Input, SparseIndexes, Output->Buffer);
return true;
}
};
template <typename Precision>
class NormalizeBuffer : public vtkm::worklet::WorkletMapField
{
protected:
Precision MinScalar;
Precision InvDeltaScalar;
bool Invert;
public:
VTKM_CONT
NormalizeBuffer(const Precision minScalar, const Precision maxScalar, bool invert)
: MinScalar(minScalar)
, Invert(invert)
{
if (maxScalar - minScalar == 0.)
{
InvDeltaScalar = MinScalar;
}
else
{
InvDeltaScalar = 1.f / (maxScalar - minScalar);
}
//std::cout<<"Min scalar "<<minScalar<<" max "<<maxScalar<<std::endl;
}
typedef void ControlSignature(FieldInOut<>);
typedef void ExecutionSignature(_1);
VTKM_EXEC
void operator()(Precision& value) const
{
value = (value - MinScalar) * InvDeltaScalar;
if (Invert)
value = 1.f - value;
}
}; //class normalize buffer
template <typename Precision>
struct NormalizeFunctor
{
vtkm::cont::ArrayHandle<Precision> Input;
bool Invert;
NormalizeFunctor(vtkm::cont::ArrayHandle<Precision> input, bool invert)
: Input(input)
, Invert(invert)
{
}
template <typename Device>
bool operator()(Device vtkmNotUsed(device))
{
vtkm::cont::Field asField("name meaningless", vtkm::cont::Field::ASSOC_POINTS, Input);
vtkm::Range range;
asField.GetRange(&range);
Precision minScalar = static_cast<Precision>(range.Min);
Precision maxScalar = static_cast<Precision>(range.Max);
vtkm::worklet::DispatcherMapField<NormalizeBuffer<Precision>, Device>(
NormalizeBuffer<Precision>(minScalar, maxScalar, Invert))
.Invoke(Input);
return true;
}
};
template <typename Precision>
ChannelBuffer<Precision> ChannelBuffer<Precision>::ExpandBuffer(
vtkm::cont::ArrayHandle<vtkm::Id> sparseIndexes,
const vtkm::Id outputSize,
vtkm::cont::ArrayHandle<Precision> signature)
{
VTKM_ASSERT(this->NumChannels == signature.GetPortalConstControl().GetNumberOfValues());
ChannelBuffer<Precision> output(this->NumChannels, outputSize);
output.SetName(this->Name);
ExpandFunctorSignature<Precision> functor(
this->Buffer, sparseIndexes, &output, outputSize, this->NumChannels, signature);
vtkm::cont::TryExecute(functor);
return output;
}
template <typename Precision>
ChannelBuffer<Precision> ChannelBuffer<Precision>::ExpandBuffer(
vtkm::cont::ArrayHandle<vtkm::Id> sparseIndexes,
const vtkm::Id outputSize,
Precision initValue)
{
ChannelBuffer<Precision> output(this->NumChannels, outputSize);
output.SetName(this->Name);
ExpandFunctor<Precision> functor(
this->Buffer, sparseIndexes, &output, outputSize, this->NumChannels, initValue);
vtkm::cont::TryExecute(functor);
return output;
}
template <typename Precision>
void ChannelBuffer<Precision>::Normalize(bool invert)
{
NormalizeFunctor<Precision> functor(this->Buffer, invert);
vtkm::cont::TryExecute(functor);
}
template <typename Precision>
struct ResizeChannelFunctor
{
ChannelBuffer<Precision>* Self;
vtkm::Int32 NumChannels;
ResizeChannelFunctor(ChannelBuffer<Precision>* self, vtkm::Int32 numChannels)
: Self(self)
, NumChannels(numChannels)
{
}
template <typename Device>
bool operator()(Device device)
{
Self->SetNumChannels(NumChannels, device);
return true;
}
};
template <typename Precision>
struct InitConstFunctor
{
ChannelBuffer<Precision>* Self;
Precision Value;
InitConstFunctor(ChannelBuffer<Precision>* self, Precision value)
: Self(self)
, Value(value)
{
}
template <typename Device>
bool operator()(Device device)
{
ChannelBufferOperations::InitConst(*Self, Value, device);
return true;
}
};
template <typename Precision>
void ChannelBuffer<Precision>::InitConst(const Precision value)
{
InitConstFunctor<Precision> functor(this, value);
vtkm::cont::TryExecute(functor);
}
template <typename Precision>
struct InitChannelFunctor
{
ChannelBuffer<Precision>* Self;
const vtkm::cont::ArrayHandle<Precision>& Signature;
InitChannelFunctor(ChannelBuffer<Precision>* self,
const vtkm::cont::ArrayHandle<Precision>& signature)
: Self(self)
, Signature(signature)
{
}
template <typename Device>
bool operator()(Device device)
{
ChannelBufferOperations::InitChannels(*Self, Signature, device);
return true;
}
};
template <typename Precision>
void ChannelBuffer<Precision>::InitChannels(const vtkm::cont::ArrayHandle<Precision>& signature)
{
InitChannelFunctor<Precision> functor(this, signature);
vtkm::cont::TryExecute(functor);
}
template <typename Precision>
void ChannelBuffer<Precision>::SetNumChannels(const vtkm::Int32 numChannels)
{
ResizeChannelFunctor<Precision> functor(this, numChannels);
vtkm::cont::TryExecute(functor);
}
// Instantiate supported types
template class ChannelBuffer<vtkm::Float32>;
template class ChannelBuffer<vtkm::Float64>;
}
}
} // namespace vtkm::rendering::raytracing

@ -0,0 +1,148 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtkm_rendering_raytracing_ChannelBuffer_h
#define vtkm_rendering_raytracing_ChannelBuffer_h
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/DeviceAdapter.h>
#include <vtkm/rendering/raytracing/RayTracingTypeDefs.h>
#include <vtkm/rendering/raytracing/Worklets.h>
#include <vtkm/rendering/vtkm_rendering_export.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <string>
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
///
/// \brief Mananges a buffer that contains many channels per value (e.g., RGBA values).
///
/// \c The ChannelBuffer class is meant to handle a buffer of values with potentially many
/// channels. While RGBA values could be placed in a Vec<T,4>, data with a large number of
/// channels (e.g., 100+ energy bins) are better handled by a raw array. Rays can have color,
/// absorption, absorption + emmision, or even track additional scalar values to support
/// standards such as Cinema. This class allows us to treat all of these differnt use cases
/// with the same type.
///
/// This class has methods that can be utilized by other VTK-m classes that already have a
/// a device dapter specified, and can be used by external callers where the call executes
/// on a device through the try execute mechanism.
///
/// \c Currently, the supported types are floating point to match the precision of the rays.
///
template <typename Precision>
class VTKM_RENDERING_EXPORT ChannelBuffer
{
protected:
vtkm::Int32 NumChannels;
vtkm::Id Size;
std::string Name;
friend class ChannelBufferOperations;
public:
vtkm::cont::ArrayHandle<Precision> Buffer;
/// Functions we want accessble outside of vtkm some of which execute
/// on a device
///
VTKM_CONT
ChannelBuffer();
VTKM_CONT
ChannelBuffer(const vtkm::Int32 numChannels, const vtkm::Id size);
VTKM_CONT
ChannelBuffer<Precision> GetChannel(const vtkm::Int32 channel);
ChannelBuffer<Precision> ExpandBuffer(vtkm::cont::ArrayHandle<vtkm::Id> sparseIndexes,
const vtkm::Id outputSize,
vtkm::cont::ArrayHandle<Precision> signature);
ChannelBuffer<Precision> ExpandBuffer(vtkm::cont::ArrayHandle<vtkm::Id> sparseIndexes,
const vtkm::Id outputSize,
Precision initValue = 1.f);
void InitConst(const Precision value);
void InitChannels(const vtkm::cont::ArrayHandle<Precision>& signature);
void Normalize(bool invert);
void SetName(const std::string name);
void Resize(const vtkm::Id newSize);
void SetNumChannels(const vtkm::Int32 numChannels);
vtkm::Int32 GetNumChannels() const;
vtkm::Id GetSize() const;
vtkm::Id GetBufferLength() const;
std::string GetName() const;
/// Functions that are calleble within vtkm where the device is already known
///
template <typename Device>
VTKM_CONT ChannelBuffer(const vtkm::Int32 size, const vtkm::Int32 numChannels, Device)
{
if (size < 1)
throw vtkm::cont::ErrorBadValue("ChannelBuffer: Size must be greater that 0");
if (numChannels < 1)
throw vtkm::cont::ErrorBadValue("ChannelBuffer: NumChannels must be greater that 0");
this->NumChannels = numChannels;
this->Size = size;
this->Buffer.PrepareForOutput(this->Size * this->NumChannels, Device());
}
template <typename Device>
VTKM_CONT void SetNumChannels(const vtkm::Int32 numChannels, Device)
{
if (numChannels < 1)
{
std::string msg = "ChannelBuffer SetNumChannels: numBins must be greater that 0";
throw vtkm::cont::ErrorBadValue(msg);
}
if (this->NumChannels == numChannels)
return;
this->NumChannels = numChannels;
this->Buffer.PrepareForOutput(this->Size * this->NumChannels, Device());
}
template <typename Device>
VTKM_CONT void Resize(const vtkm::Id newSize, Device device)
{
if (newSize < 0)
throw vtkm::cont::ErrorBadValue("ChannelBuffer resize: Size must be greater than -1 ");
this->Size = newSize;
this->Buffer.PrepareForOutput(this->Size * static_cast<vtkm::Id>(NumChannels), device);
}
};
}
}
} // namespace vtkm::rendering::raytracing
#endif

@ -0,0 +1,145 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtkm_rendering_raytracing_ChannelBuffer_Operations_h
#define vtkm_rendering_raytracing_ChannelBuffer_Operations_h
#include <vtkm/Types.h>
#include <vtkm/rendering/raytracing/ChannelBuffer.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/WorkletMapField.h>
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
namespace detail
{
class CompactBuffer : public vtkm::worklet::WorkletMapField
{
protected:
const vtkm::Id NumChannels; // the number of channels in the buffer
public:
VTKM_CONT
CompactBuffer(const vtkm::Int32 numChannels)
: NumChannels(numChannels)
{
}
typedef void ControlSignature(FieldIn<>, WholeArrayIn<>, FieldIn<>, WholeArrayOut<>);
typedef void ExecutionSignature(_1, _2, _3, _4, WorkIndex);
template <typename InBufferPortalType, typename OutBufferPortalType>
VTKM_EXEC void operator()(const vtkm::UInt8& mask,
const InBufferPortalType& inBuffer,
const vtkm::Id& offset,
OutBufferPortalType& outBuffer,
const vtkm::Id& index) const
{
if (mask == 0)
{
return;
}
vtkm::Id inIndex = index * NumChannels;
vtkm::Id outIndex = offset * NumChannels;
for (vtkm::Int32 i = 0; i < NumChannels; ++i)
{
BOUNDS_CHECK(inBuffer, inIndex + i);
BOUNDS_CHECK(outBuffer, outIndex + i);
outBuffer.Set(outIndex + i, inBuffer.Get(inIndex + i));
}
}
}; //class Compact
class InitBuffer : public vtkm::worklet::WorkletMapField
{
protected:
vtkm::Int32 NumChannels;
public:
VTKM_CONT
InitBuffer(const vtkm::Int32 numChannels)
: NumChannels(numChannels)
{
}
typedef void ControlSignature(FieldOut<>, WholeArrayIn<>);
typedef void ExecutionSignature(_1, _2, WorkIndex);
template <typename ValueType, typename PortalType>
VTKM_EXEC void operator()(ValueType& outValue,
const PortalType& source,
const vtkm::Id& index) const
{
outValue = source.Get(index % NumChannels);
}
}; //class InitBuffer
} // namespace detail
class ChannelBufferOperations
{
public:
template <typename Device, typename Precision>
static void Compact(ChannelBuffer<Precision>& buffer,
vtkm::cont::ArrayHandle<UInt8>& masks,
const vtkm::Id& newSize,
Device)
{
vtkm::cont::ArrayHandle<vtkm::Id> offsets;
offsets.PrepareForOutput(buffer.Size, Device());
vtkm::cont::ArrayHandleCast<vtkm::Id, vtkm::cont::ArrayHandle<vtkm::UInt8>> castedMasks(masks);
vtkm::cont::DeviceAdapterAlgorithm<Device>::ScanExclusive(castedMasks, offsets);
vtkm::cont::ArrayHandle<Precision> compactedBuffer;
compactedBuffer.PrepareForOutput(newSize * buffer.NumChannels, Device());
vtkm::worklet::DispatcherMapField<detail::CompactBuffer, Device>(
detail::CompactBuffer(buffer.NumChannels))
.Invoke(masks, buffer.Buffer, offsets, compactedBuffer);
buffer.Buffer = compactedBuffer;
buffer.Size = newSize;
}
template <typename Device, typename Precision>
static void InitChannels(ChannelBuffer<Precision>& buffer,
vtkm::cont::ArrayHandle<Precision> sourceSignature,
Device)
{
if (sourceSignature.GetNumberOfValues() != buffer.NumChannels)
{
std::string msg = "ChannelBuffer: number of bins in sourse signature must match NumChannels";
throw vtkm::cont::ErrorBadValue(msg);
}
vtkm::worklet::DispatcherMapField<detail::InitBuffer, Device>(
detail::InitBuffer(buffer.NumChannels))
.Invoke(buffer.Buffer, sourceSignature);
}
template <typename Device, typename Precision>
static void InitConst(ChannelBuffer<Precision>& buffer, const Precision value, Device)
{
vtkm::worklet::DispatcherMapField<MemSet<Precision>, Device>(MemSet<Precision>(value))
.Invoke(buffer.Buffer);
}
};
}
}
} // namespace vtkm::rendering::raytracing
#endif

@ -0,0 +1,68 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_rendering_raytracing_Connectivity_Base_h
#define vtk_m_rendering_raytracing_Connectivity_Base_h
#include <vtkm/rendering/raytracing/Logger.h>
#include <vtkm/rendering/raytracing/Ray.h>
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
class ConnectivityBase
{
public:
enum IntegrationMode
{
Volume,
Energy
};
ConnectivityBase() {}
virtual ~ConnectivityBase() {}
virtual void Trace(Ray<vtkm::Float64>& rays) = 0;
virtual void Trace(Ray<vtkm::Float32>& rays) = 0;
virtual void SetVolumeData(const vtkm::cont::Field& scalarField,
const vtkm::Range& scalarBounds) = 0;
virtual void SetEnergyData(const vtkm::cont::Field& absorbtion,
const vtkm::Int32 numBins,
const vtkm::cont::Field& emission = vtkm::cont::Field()) = 0;
virtual void SetBackgroundColor(const vtkm::Vec<vtkm::Float32, 4>& backgroundColor) = 0;
virtual void SetCompositeBackground(bool on) = 0;
virtual void SetSampleDistance(const vtkm::Float32& distance) = 0;
virtual void SetColorMap(
const vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& colorMap) = 0;
}; // class ConnectivityBase
}
}
} // namespace vtkm::rendering::raytracing
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,124 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_rendering_raytracing_ConnectivityTracerFactory_h
#define vtk_m_rendering_raytracing_ConnectivityTracerFactory_h
#include <vtkm/rendering/raytracing/ConnectivityTracer.h>
#include <vtkm/rendering/raytracing/RayTracingTypeDefs.h>
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
class ConnectivityTracerFactory
{
public:
enum TracerType
{
Unsupported = 0,
Structured = 1,
Unstructured = 2,
UnstructuredHex = 3,
UnstructuredTet = 4,
UnstructuredWedge = 5,
UnstructuredPyramid = 6
};
//----------------------------------------------------------------------------
static TracerType DetectCellSetType(const vtkm::cont::DynamicCellSet& cellset)
{
TracerType type = Unsupported;
if (cellset.IsSameType(vtkm::cont::CellSetExplicit<>()))
{
type = Unstructured;
}
else if (cellset.IsSameType(vtkm::cont::CellSetSingleType<>()))
{
vtkm::cont::CellSetSingleType<> singleType = cellset.Cast<vtkm::cont::CellSetSingleType<>>();
//
// Now we need to determine what type of cells this holds
//
vtkm::cont::ArrayHandleConstant<vtkm::UInt8> shapes =
singleType.GetShapesArray(vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
vtkm::UInt8 shapeType = shapes.GetPortalConstControl().Get(0);
if (shapeType == CELL_SHAPE_HEXAHEDRON)
type = UnstructuredHex;
if (shapeType == CELL_SHAPE_TETRA)
type = UnstructuredTet;
if (shapeType == CELL_SHAPE_WEDGE)
type = UnstructuredWedge;
if (shapeType == CELL_SHAPE_PYRAMID)
type = UnstructuredPyramid;
}
else if (cellset.IsSameType(vtkm::cont::CellSetStructured<3>()))
{
type = Structured;
}
return type;
}
//----------------------------------------------------------------------------
static ConnectivityBase* CreateTracer(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords)
{
TracerType type = DetectCellSetType(cellset);
if (type == Unstructured)
{
UnstructuredMeshConn meshConn(cellset, coords);
return new ConnectivityTracer<CELL_SHAPE_ZOO, UnstructuredMeshConn>(meshConn);
}
else if (type == UnstructuredHex)
{
UnstructuredMeshConnSingleType meshConn(cellset, coords);
return new ConnectivityTracer<CELL_SHAPE_HEXAHEDRON, UnstructuredMeshConnSingleType>(
meshConn);
}
else if (type == UnstructuredWedge)
{
UnstructuredMeshConnSingleType meshConn(cellset, coords);
return new ConnectivityTracer<CELL_SHAPE_WEDGE, UnstructuredMeshConnSingleType>(meshConn);
}
else if (type == UnstructuredTet)
{
UnstructuredMeshConnSingleType meshConn(cellset, coords);
return new ConnectivityTracer<CELL_SHAPE_TETRA, UnstructuredMeshConnSingleType>(meshConn);
}
else if (type == Structured)
{
StructuredMeshConn meshConn(cellset, coords);
return new ConnectivityTracer<CELL_SHAPE_STRUCTURED, StructuredMeshConn>(meshConn);
}
else
{
throw vtkm::cont::ErrorBadValue("Connectivity tracer: cell set type unsupported");
}
return NULL;
}
};
}
}
} // namespace vtkm::rendering::raytracing
#endif

@ -0,0 +1,77 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <vtkm/rendering/raytracing/Logger.h>
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
Logger* Logger::Instance = NULL;
Logger::Logger()
{
}
Logger::~Logger()
{
Stream.str("");
}
Logger* Logger::GetInstance()
{
if (Instance == NULL)
{
Instance = new Logger();
}
return Instance;
}
std::stringstream& Logger::GetStream()
{
return Stream;
}
void Logger::Clear()
{
Stream.str("");
while (!Entries.empty())
{
Entries.pop();
}
}
void Logger::OpenLogEntry(const std::string& entryName)
{
Stream << entryName << " "
<< "<\n";
Entries.push(entryName);
}
void Logger::CloseLogEntry(const vtkm::Float64& entryTime)
{
this->Stream << "total_time " << entryTime << "\n";
this->Stream << this->Entries.top() << " >\n";
Entries.pop();
}
}
}
} // namespace vtkm::renderng::raytracing

@ -17,8 +17,14 @@
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_rendering_raytracing_Loggable_h
#define vtk_m_rendering_raytracing_Loggable_h
#include <vtkm/rendering/raytracing/Ray.h>
#include <sstream>
#include <stack>
#include <vtkm/Types.h>
#include <vtkm/rendering/vtkm_rendering_export.h>
namespace vtkm
{
@ -27,9 +33,30 @@ namespace rendering
namespace raytracing
{
RayBase::~RayBase()
class VTKM_RENDERING_EXPORT Logger
{
}
public:
~Logger();
static Logger* GetInstance();
void OpenLogEntry(const std::string& entryName);
void CloseLogEntry(const vtkm::Float64& entryTime);
void Clear();
template <typename T>
void AddLogData(const std::string key, const T& value)
{
this->Stream << key << " " << value << "\n";
}
std::stringstream& GetStream();
protected:
Logger();
Logger(Logger const&);
std::stringstream Stream;
static class Logger* Instance;
std::stack<std::string> Entries;
};
}
}
} // namespace vtkm::rendering::raytracing
#endif

@ -0,0 +1,822 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_rendering_raytracing_MeshConnectivityBuilder_h
#define vtk_m_rendering_raytracing_MeshConnectivityBuilder_h
#include <vtkm/cont/CellSetExplicit.h>
#include <vtkm/cont/CellSetSingleType.h>
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/CoordinateSystem.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/WorkletMapTopology.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/raytracing/CellTables.h>
#include <vtkm/rendering/raytracing/Logger.h>
#include <vtkm/rendering/raytracing/MortonCodes.h>
#include <vtkm/rendering/raytracing/RayTracingTypeDefs.h>
#include <vtkm/rendering/raytracing/Worklets.h>
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
struct IsExternal
{
VTKM_EXEC_CONT
inline bool operator()(const vtkm::Id& x) const { return (x < 0); }
}; //struct IsExternal
class CountFaces : public vtkm::worklet::WorkletMapField
{
public:
VTKM_CONT
CountFaces() {}
typedef void ControlSignature(WholeArrayIn<>, FieldOut<>);
typedef void ExecutionSignature(_1, _2, WorkIndex);
template <typename ShapePortalType>
VTKM_EXEC inline void operator()(const ShapePortalType& shapes,
vtkm::Id& faces,
const vtkm::Id& index) const
{
BOUNDS_CHECK(shapes, index);
vtkm::UInt8 shapeType = shapes.Get(index);
if (shapeType == vtkm::CELL_SHAPE_TETRA)
{
faces = 4;
}
else if (shapeType == vtkm::CELL_SHAPE_HEXAHEDRON)
{
faces = 6;
}
else if (shapeType == vtkm::CELL_SHAPE_WEDGE)
{
faces = 5;
}
else if (shapeType == vtkm::CELL_SHAPE_PYRAMID)
{
faces = 5;
}
else
{
faces = 0;
}
}
}; //class CountFaces
class MortonNeighbor : public vtkm::worklet::WorkletMapField
{
public:
VTKM_CONT
MortonNeighbor() {}
typedef void ControlSignature(WholeArrayIn<>,
ExecObject,
WholeArrayIn<>,
WholeArrayIn<>,
WholeArrayIn<>,
WholeArrayOut<>);
typedef void ExecutionSignature(_1, _2, WorkIndex, _3, _4, _5, _6);
VTKM_EXEC
inline vtkm::Int32 GetShapeOffset(const vtkm::UInt8& shapeType) const
{
//TODO: This might be better as if if if
vtkm::Int32 tableOffset = 0;
if (shapeType == vtkm::CELL_SHAPE_TETRA)
{
tableOffset = FaceLookUp[1][0];
}
else if (shapeType == vtkm::CELL_SHAPE_HEXAHEDRON)
{
tableOffset = FaceLookUp[0][0];
}
else if (shapeType == vtkm::CELL_SHAPE_WEDGE)
{
tableOffset = FaceLookUp[2][0];
}
else if (shapeType == vtkm::CELL_SHAPE_PYRAMID)
{
tableOffset = FaceLookUp[3][0];
}
else
printf("Error shape not recognized %d\n", (int)shapeType);
return tableOffset;
}
VTKM_EXEC
inline bool IsIn(const vtkm::Id& needle,
const vtkm::Vec<vtkm::Id, 4>& heystack,
const vtkm::Int32& numIndices) const
{
bool isIn = false;
for (vtkm::Int32 i = 0; i < numIndices; ++i)
{
if (needle == heystack[i])
isIn = true;
}
return isIn;
}
template <typename MortonPortalType,
typename ConnPortalType,
typename ShapePortalType,
typename OffsetPortalType,
typename ExternalFaceFlagType>
VTKM_EXEC inline void operator()(
const MortonPortalType& mortonCodes,
vtkm::exec::ExecutionWholeArray<vtkm::Vec<vtkm::Id, 3>>& faceIdPairs,
const vtkm::Id& index,
const ConnPortalType& connectivity,
const ShapePortalType& shapes,
const OffsetPortalType& offsets,
ExternalFaceFlagType& flags) const
{
if (index == 0)
{
return;
}
vtkm::Id currentIndex = index - 1;
BOUNDS_CHECK(mortonCodes, index);
vtkm::UInt32 myCode = mortonCodes.Get(index);
BOUNDS_CHECK(mortonCodes, currentIndex);
vtkm::UInt32 myNeighbor = mortonCodes.Get(currentIndex);
bool isInternal = false;
vtkm::Id connectedCell = -1;
while (currentIndex > -1 && myCode == myNeighbor)
{
myNeighbor = mortonCodes.Get(currentIndex);
// just because the codes are equal does not mean that
// they are the same face. We need to double check.
if (myCode == myNeighbor)
{
//get the index of the shape face in the table.
BOUNDS_CHECK(faceIdPairs, index);
vtkm::Id cellId1 = faceIdPairs.Get(index)[0];
BOUNDS_CHECK(faceIdPairs, currentIndex);
vtkm::Id cellId2 = faceIdPairs.Get(currentIndex)[0];
BOUNDS_CHECK(shapes, cellId1);
BOUNDS_CHECK(shapes, cellId2);
vtkm::Id shape1Offset = GetShapeOffset(shapes.Get(cellId1)) + faceIdPairs.Get(index)[1];
vtkm::Id shape2Offset =
GetShapeOffset(shapes.Get(cellId2)) + faceIdPairs.Get(currentIndex)[1];
vtkm::Int32 icount1 = ShapesFaceList[shape1Offset][0];
vtkm::Int32 icount2 = ShapesFaceList[shape2Offset][0];
//Check to see if we have the same number of idices
if (icount1 != icount2)
continue;
//TODO: we can do better than this
vtkm::Vec<vtkm::Id, 4> indices1;
vtkm::Vec<vtkm::Id, 4> indices2;
for (vtkm::Int32 i = 1; i <= ShapesFaceList[shape1Offset][0]; ++i)
{
BOUNDS_CHECK(offsets, cellId1);
BOUNDS_CHECK(offsets, cellId2);
BOUNDS_CHECK(connectivity, (offsets.Get(cellId1) + ShapesFaceList[shape1Offset][i]));
BOUNDS_CHECK(connectivity, (offsets.Get(cellId2) + ShapesFaceList[shape2Offset][i]));
indices1[i - 1] =
connectivity.Get(offsets.Get(cellId1) + ShapesFaceList[shape1Offset][i]);
indices2[i - 1] =
connectivity.Get(offsets.Get(cellId2) + ShapesFaceList[shape2Offset][i]);
}
bool isEqual = true;
for (vtkm::Int32 i = 0; i < ShapesFaceList[shape1Offset][0]; ++i)
{
if (!IsIn(indices1[i], indices2, ShapesFaceList[shape1Offset][0]))
isEqual = false;
}
if (isEqual)
{
isInternal = true;
connectedCell = cellId2;
break;
}
}
currentIndex--;
}
//this means that this cell is resposible for both itself and the other cell
//set the connecttion for the other cell
if (isInternal)
{
BOUNDS_CHECK(faceIdPairs, index);
vtkm::Vec<vtkm::Id, 3> facePair = faceIdPairs.Get(index);
vtkm::Id myCell = facePair[0];
facePair[2] = connectedCell;
BOUNDS_CHECK(faceIdPairs, index);
faceIdPairs.Set(index, facePair);
BOUNDS_CHECK(faceIdPairs, currentIndex);
facePair = faceIdPairs.Get(currentIndex);
facePair[2] = myCell;
BOUNDS_CHECK(faceIdPairs, currentIndex);
faceIdPairs.Set(currentIndex, facePair);
BOUNDS_CHECK(flags, currentIndex);
flags.Set(currentIndex, myCell);
BOUNDS_CHECK(flags, index);
flags.Set(index, connectedCell);
}
}
}; //class Neighbor
class ExternalTriangles : public vtkm::worklet::WorkletMapField
{
public:
VTKM_CONT
ExternalTriangles() {}
typedef void ControlSignature(FieldIn<>,
WholeArrayIn<>,
WholeArrayIn<>,
WholeArrayIn<>,
WholeArrayOut<>,
FieldIn<>);
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6);
template <typename ShapePortalType,
typename InIndicesPortalType,
typename OutIndicesPortalType,
typename ShapeOffsetsPortal>
VTKM_EXEC inline void operator()(const vtkm::Vec<vtkm::Id, 3>& faceIdPair,
const ShapePortalType& shapes,
const ShapeOffsetsPortal& shapeOffsets,
const InIndicesPortalType& indices,
const OutIndicesPortalType& outputIndices,
const vtkm::Id& outputOffset) const
{
vtkm::Id cellId = faceIdPair[0];
BOUNDS_CHECK(shapeOffsets, cellId);
vtkm::Id offset = shapeOffsets.Get(cellId);
BOUNDS_CHECK(shapes, cellId);
vtkm::Int32 shapeId = static_cast<vtkm::Int32>(shapes.Get(cellId));
vtkm::Int32 shapesFaceOffset = FaceLookUp[CellTypeLookUp[shapeId]][0];
if (shapesFaceOffset == -1)
{
printf("Unsupported Shape Type %d\n", shapeId);
return;
}
vtkm::Vec<vtkm::Id, 4> faceIndices(-1, -1, -1, -1);
vtkm::Int32 tableIndex = static_cast<vtkm::Int32>(shapesFaceOffset + faceIdPair[1]);
const vtkm::Int32 numIndices = ShapesFaceList[tableIndex][0];
for (vtkm::Int32 i = 1; i <= numIndices; ++i)
{
BOUNDS_CHECK(indices, offset + ShapesFaceList[tableIndex][i]);
faceIndices[i - 1] = indices.Get(offset + ShapesFaceList[tableIndex][i]);
}
vtkm::Vec<vtkm::Id, 4> triangle;
triangle[0] = cellId;
triangle[1] = faceIndices[0];
triangle[2] = faceIndices[1];
triangle[3] = faceIndices[2];
BOUNDS_CHECK(outputIndices, outputOffset);
outputIndices.Set(outputOffset, triangle);
if (numIndices == 4)
{
triangle[1] = faceIndices[0];
triangle[2] = faceIndices[2];
triangle[3] = faceIndices[3];
BOUNDS_CHECK(outputIndices, outputOffset + 1);
outputIndices.Set(outputOffset + 1, triangle);
}
}
}; //class External Triangles
// Face conn was originally used for filtering out internal
// faces and was sorted with faces. To make it usable,
// we need to scatter back the connectivity into the original
// cell order, i.e., conn for cell 0 at 0,1,2,3,4,5
class WriteFaceConn : public vtkm::worklet::WorkletMapField
{
public:
VTKM_CONT
WriteFaceConn() {}
typedef void ControlSignature(FieldIn<>, WholeArrayIn<>, ExecObject);
typedef void ExecutionSignature(_1, _2, _3);
template <typename FaceOffsetsPortalType>
VTKM_EXEC inline void operator()(const vtkm::Vec<vtkm::Id, 3>& faceIdPair,
const FaceOffsetsPortalType& faceOffsets,
vtkm::exec::ExecutionWholeArray<vtkm::Id>& faceConn) const
{
vtkm::Id cellId = faceIdPair[0];
BOUNDS_CHECK(faceOffsets, cellId);
vtkm::Id faceOffset = faceOffsets.Get(cellId) + faceIdPair[1]; // cellOffset ++ faceId
BOUNDS_CHECK(faceConn, faceOffset);
faceConn.Set(faceOffset, faceIdPair[2]);
}
}; //class WriteFaceConn
// Each one of size segments will process
// one face of the hex and domain
VTKM_EXEC_CONSTANT
static vtkm::Int32 SegmentToFace[6] = { 0, 2, 1, 3, 4, 5 };
// Each face/segment has 2 varying dimensions
VTKM_EXEC_CONSTANT
static vtkm::Int32 SegmentDirections[6][2] = { { 0, 2 }, //face 0 and 2 have the same directions
{ 0, 2 }, { 1, 2 }, //1 and 3
{ 1, 2 }, { 0, 1 }, // 4 and 5
{ 0, 1 } };
class StructuredExternalTriangles : public vtkm::worklet::WorkletMapField
{
protected:
typedef vtkm::exec::ConnectivityStructured<vtkm::TopologyElementTagPoint,
vtkm::TopologyElementTagCell,
3>
ConnType;
ConnType Connectivity;
vtkm::Id Segments[7];
vtkm::Id3 CellDims;
public:
VTKM_CONT
StructuredExternalTriangles(const ConnType& connectivity)
: Connectivity(connectivity)
{
vtkm::Id3 cellDims = Connectivity.GetPointDimensions();
cellDims[0] -= 1;
cellDims[1] -= 1;
cellDims[2] -= 1;
CellDims = cellDims;
//We have 6 segments for each of the six faces.
Segments[0] = 0;
// 0-1 = the two faces parallel to the x-z plane
Segments[1] = cellDims[0] * cellDims[2];
Segments[2] = Segments[1] + Segments[1];
// 2-3 parallel to the y-z plane
Segments[3] = Segments[2] + cellDims[1] * cellDims[2];
Segments[4] = Segments[3] + cellDims[1] * cellDims[2];
// 4-5 parallel to the x-y plane
Segments[5] = Segments[4] + cellDims[1] * cellDims[0];
Segments[6] = Segments[5] + cellDims[1] * cellDims[0];
}
typedef void ControlSignature(FieldIn<>, WholeArrayOut<>);
typedef void ExecutionSignature(_1, _2);
template <typename TrianglePortalType>
VTKM_EXEC inline void operator()(const vtkm::Id& index, TrianglePortalType& triangles) const
{
//
// We get one index per extenal face
//
//
// Cell face to extract which is also the domain
// face in this segment
//
vtkm::Int32 segment;
for (segment = 0; index >= Segments[segment + 1]; ++segment)
;
if (segment >= 6)
{
printf("OUT OF BOUDNS %d", (int)index);
}
vtkm::Int32 cellFace = SegmentToFace[segment];
// Face relative directions of the
// 2 varying coordinates.
vtkm::Int32 dir1, dir2;
dir1 = SegmentDirections[segment][0];
dir2 = SegmentDirections[segment][1];
// For each face, we will have a relative offset to
// the "bottom corner of the face. Three are at the
// origin. and we have to ajust for the other faces.
vtkm::Id3 cellIndex(0, 0, 0);
if (cellFace == 1)
cellIndex[0] = CellDims[0] - 1;
if (cellFace == 2)
cellIndex[1] = CellDims[1] - 1;
if (cellFace == 5)
cellIndex[2] = CellDims[2] - 1;
// index is the global index of all external faces
// the offset is the relative index of the cell
// on the current 2d face
vtkm::Id offset = index - Segments[segment];
vtkm::Id dir1Offset = offset % CellDims[dir1];
vtkm::Id dir2Offset = offset / CellDims[dir1];
cellIndex[dir1] = cellIndex[dir1] + dir1Offset;
cellIndex[dir2] = cellIndex[dir2] + dir2Offset;
vtkm::Id cellId = Connectivity.LogicalToFlatToIndex(cellIndex);
vtkm::VecVariable<vtkm::Id, 8> cellIndices = Connectivity.GetIndices(cellId);
// Look up the offset into the face list for each cell type
// This should always be zero, but in case this table changes I don't
// want to break anything.
vtkm::Int32 shapesFaceOffset = FaceLookUp[CellTypeLookUp[CELL_SHAPE_HEXAHEDRON]][0];
vtkm::Vec<vtkm::Id, 4> faceIndices;
vtkm::Int32 tableIndex = shapesFaceOffset + cellFace;
// Load the face
for (vtkm::Int32 i = 1; i <= 4; ++i)
{
faceIndices[i - 1] = cellIndices[ShapesFaceList[tableIndex][i]];
}
const vtkm::Id outputOffset = index * 2;
vtkm::Vec<vtkm::Id, 4> triangle;
triangle[0] = cellId;
triangle[1] = faceIndices[0];
triangle[2] = faceIndices[1];
triangle[3] = faceIndices[2];
BOUNDS_CHECK(triangles, outputOffset);
triangles.Set(outputOffset, triangle);
triangle[1] = faceIndices[0];
triangle[2] = faceIndices[2];
triangle[3] = faceIndices[3];
BOUNDS_CHECK(triangles, outputOffset);
triangles.Set(outputOffset + 1, triangle);
}
}; //class StructuredExternalTriangles
//If with output faces or triangles, we still have to calculate the size of the output
//array. TODO: switch to faces only
class CountExternalTriangles : public vtkm::worklet::WorkletMapField
{
public:
VTKM_CONT
CountExternalTriangles() {}
typedef void ControlSignature(FieldIn<>, WholeArrayIn<>, FieldOut<>);
typedef void ExecutionSignature(_1, _2, _3);
template <typename ShapePortalType>
VTKM_EXEC inline void operator()(const vtkm::Vec<vtkm::Id, 3>& faceIdPair,
const ShapePortalType& shapes,
vtkm::Id& triangleCount) const
{
vtkm::Id cellId = faceIdPair[0];
vtkm::Id cellFace = faceIdPair[1];
vtkm::Int32 shapeType = static_cast<vtkm::Int32>(shapes.Get(cellId));
vtkm::Int32 faceStartIndex = FaceLookUp[CellTypeLookUp[shapeType]][0];
if (faceStartIndex == -1)
{
//Unsupported Shape Type this should never happen
triangleCount = 0;
return;
}
vtkm::Int32 faceType = ShapesFaceList[faceStartIndex + cellFace][0];
// The face will either have 4 or 3 indices, so quad or tri
triangleCount = (faceType == 4) ? 2 : 1;
//faceConn.Set(faceOffset, faceIdPair[2]);
}
}; //class WriteFaceConn
template <typename DeviceAdapter>
class MeshConnectivityBuilder
{
public:
MeshConnectivityBuilder() {}
~MeshConnectivityBuilder() {}
VTKM_CONT
void BuildConnectivity(vtkm::cont::CellSetSingleType<>& cellSetUnstructured,
DynamicArrayHandleExplicitCoordinateSystem& coordinates,
vtkm::Bounds coordsBounds)
{
Logger* logger = Logger::GetInstance();
logger->OpenLogEntry("mesh_conn");
logger->AddLogData("device", GetDeviceString(DeviceAdapter()));
vtkm::cont::Timer<DeviceAdapter> timer;
vtkm::Float32 BoundingBox[6];
BoundingBox[0] = vtkm::Float32(coordsBounds.X.Min);
BoundingBox[1] = vtkm::Float32(coordsBounds.X.Max);
BoundingBox[2] = vtkm::Float32(coordsBounds.Y.Min);
BoundingBox[3] = vtkm::Float32(coordsBounds.Y.Max);
BoundingBox[4] = vtkm::Float32(coordsBounds.Z.Min);
BoundingBox[5] = vtkm::Float32(coordsBounds.Z.Max);
const vtkm::cont::ArrayHandleConstant<vtkm::UInt8> shapes = cellSetUnstructured.GetShapesArray(
vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
const vtkm::cont::ArrayHandle<vtkm::Id> conn = cellSetUnstructured.GetConnectivityArray(
vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
const vtkm::cont::ArrayHandleCounting<vtkm::Id> shapeOffsets =
cellSetUnstructured.GetIndexOffsetArray(vtkm::TopologyElementTagPoint(),
vtkm::TopologyElementTagCell());
vtkm::cont::ArrayHandle<vtkm::Id> faceConnectivity;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 3>> cellFaceId;
this->GenerateFaceConnnectivity(cellSetUnstructured,
shapes,
conn,
shapeOffsets,
coordinates,
faceConnectivity,
cellFaceId,
BoundingBox);
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> externalTriangles;
//Extenal Faces
externalTriangles =
this->ExtractExternalFaces(cellFaceId, faceConnectivity, shapes, conn, shapeOffsets);
// scatter the coonectivity into the original order
vtkm::worklet::DispatcherMapField<WriteFaceConn>(WriteFaceConn())
.Invoke(
cellFaceId, this->FaceOffsets, vtkm::exec::ExecutionWholeArray<vtkm::Id>(faceConnectivity));
FaceConnectivity = faceConnectivity;
OutsideTriangles = externalTriangles;
vtkm::Float64 time = timer.GetElapsedTime();
logger->CloseLogEntry(time);
}
VTKM_CONT
void BuildConnectivity(vtkm::cont::CellSetExplicit<>& cellSetUnstructured,
DynamicArrayHandleExplicitCoordinateSystem& coordinates,
vtkm::Bounds coordsBounds)
{
Logger* logger = Logger::GetInstance();
logger->OpenLogEntry("meah_conn");
logger->AddLogData("device", GetDeviceString(DeviceAdapter()));
vtkm::cont::Timer<DeviceAdapter> timer;
vtkm::Float32 BoundingBox[6];
BoundingBox[0] = vtkm::Float32(coordsBounds.X.Min);
BoundingBox[1] = vtkm::Float32(coordsBounds.X.Max);
BoundingBox[2] = vtkm::Float32(coordsBounds.Y.Min);
BoundingBox[3] = vtkm::Float32(coordsBounds.Y.Max);
BoundingBox[4] = vtkm::Float32(coordsBounds.Z.Min);
BoundingBox[5] = vtkm::Float32(coordsBounds.Z.Max);
const vtkm::cont::ArrayHandle<vtkm::UInt8> shapes = cellSetUnstructured.GetShapesArray(
vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
const vtkm::cont::ArrayHandle<vtkm::Id> conn = cellSetUnstructured.GetConnectivityArray(
vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
const vtkm::cont::ArrayHandle<vtkm::Id> shapeOffsets = cellSetUnstructured.GetIndexOffsetArray(
vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
vtkm::cont::ArrayHandle<vtkm::Id> faceConnectivity;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 3>> cellFaceId;
this->GenerateFaceConnnectivity(cellSetUnstructured,
shapes,
conn,
shapeOffsets,
coordinates,
faceConnectivity,
cellFaceId,
BoundingBox);
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> externalTriangles;
//
//Extenal Faces
externalTriangles =
this->ExtractExternalFaces(cellFaceId, faceConnectivity, shapes, conn, shapeOffsets);
// scatter the coonectivity into the original order
vtkm::worklet::DispatcherMapField<WriteFaceConn>(WriteFaceConn())
.Invoke(
cellFaceId, this->FaceOffsets, vtkm::exec::ExecutionWholeArray<vtkm::Id>(faceConnectivity));
FaceConnectivity = faceConnectivity;
OutsideTriangles = externalTriangles;
vtkm::Float64 time = timer.GetElapsedTime();
logger->CloseLogEntry(time);
}
// Should we just make this name BuildConnectivity?
VTKM_CONT
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> ExternalTrianglesStructured(
vtkm::cont::CellSetStructured<3>& cellSetStructured)
{
vtkm::cont::Timer<DeviceAdapter> timer;
vtkm::Id3 cellDims = cellSetStructured.GetCellDimensions();
vtkm::Id numFaces =
cellDims[0] * cellDims[1] * 2 + cellDims[1] * cellDims[2] * 2 + cellDims[2] * cellDims[0] * 2;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> triangles;
triangles.PrepareForOutput(numFaces * 2, DeviceAdapter());
vtkm::cont::ArrayHandleCounting<vtkm::Id> counting(0, 1, numFaces);
vtkm::worklet::DispatcherMapField<StructuredExternalTriangles>(
StructuredExternalTriangles(cellSetStructured.PrepareForInput(
DeviceAdapter(), vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell())))
.Invoke(counting, triangles);
vtkm::Float64 time = timer.GetElapsedTime();
Logger::GetInstance()->AddLogData("structured_external_faces", time);
;
return triangles;
}
vtkm::cont::ArrayHandle<vtkm::Id> GetFaceConnectivity() { return FaceConnectivity; }
vtkm::cont::ArrayHandle<vtkm::Id> GetFaceOffsets() { return FaceOffsets; }
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> GetExternalTriangles()
{
return OutsideTriangles;
}
protected:
template <typename CellSetType,
typename ShapeHandleType,
typename ConnHandleType,
typename OffsetsHandleType>
VTKM_CONT void GenerateFaceConnnectivity(
const CellSetType cellSet,
const ShapeHandleType shapes,
const ConnHandleType conn,
const OffsetsHandleType shapeOffsets,
DynamicArrayHandleExplicitCoordinateSystem& coordinates,
vtkm::cont::ArrayHandle<vtkm::Id>& faceConnectivity,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 3>>& cellFaceId,
vtkm::Float32 BoundingBox[6])
{
vtkm::cont::Timer<DeviceAdapter> timer;
vtkm::Id numCells = shapes.GetNumberOfValues();
/*-----------------------------------------------------------------*/
// Count the number of total faces in the cell set
vtkm::cont::ArrayHandle<vtkm::Id> facesPerCell;
vtkm::worklet::DispatcherMapField<CountFaces, DeviceAdapter>(CountFaces())
.Invoke(shapes, facesPerCell);
vtkm::Id totalFaces = 0;
totalFaces =
vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::Reduce(facesPerCell, vtkm::Id(0));
// Calculate the offsets so each cell knows where to insert the morton code
// for each face
vtkm::cont::ArrayHandle<vtkm::Id> cellOffsets;
cellOffsets.PrepareForOutput(numCells, DeviceAdapter());
vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::ScanExclusive(facesPerCell, cellOffsets);
// cell offsets also serve as the offsets into the array that tracks connectivity.
// For example, we have a hex with 6 faces and each face connects to another cell.
// The connecting cells (from each face) are stored beginning at index cellOffsets[cellId]
this->FaceOffsets = cellOffsets;
// We are creating a spatial hash based on morton codes calculated
// from the centriod (point average) of each face. Each centroid is
// calculated in way (consistant order of floating point calcs) that
// ensures that each face maps to the same morton code. It is possbilbe
// that two non-connecting faces map to the same morton code, but if
// if a face has a matching face from another cell, it will be mapped
// to the same morton code. We check for this.
// set up everyting we need to gen morton codes
vtkm::Vec<vtkm::Float32, 3> inverseExtent;
inverseExtent[0] = 1.f / (BoundingBox[1] - BoundingBox[0]);
inverseExtent[1] = 1.f / (BoundingBox[3] - BoundingBox[2]);
inverseExtent[2] = 1.f / (BoundingBox[5] - BoundingBox[4]);
vtkm::Vec<vtkm::Float32, 3> minPoint;
minPoint[0] = BoundingBox[0];
minPoint[1] = BoundingBox[2];
minPoint[2] = BoundingBox[4];
// Morton Codes are created for the centroid of each face.
// cellFaceId:
// 0) Cell that the face belongs to
// 1) Face of the the cell (e.g., hex will have 6 faces and this is 1 of the 6)
// 2) cell id of the cell that connects to the corresponding face (1)
vtkm::cont::ArrayHandle<vtkm::UInt32> faceMortonCodes;
cellFaceId.PrepareForOutput(totalFaces, DeviceAdapter());
faceMortonCodes.PrepareForOutput(totalFaces, DeviceAdapter());
vtkm::worklet::DispatcherMapTopology<MortonCodeFace, DeviceAdapter>(
MortonCodeFace(inverseExtent, minPoint))
.Invoke(cellSet, coordinates, cellOffsets, faceMortonCodes, cellFaceId);
// Sort the "faces" (i.e., morton codes)
vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::SortByKey(faceMortonCodes, cellFaceId);
// Allocate space for the final face-to-face conectivity
faceConnectivity.PrepareForOutput(totalFaces, DeviceAdapter());
// Initialize All connecting faces to -1 (connects to nothing)
vtkm::worklet::DispatcherMapField<MemSet<vtkm::Id>, DeviceAdapter>(MemSet<vtkm::Id>(-1))
.Invoke(faceConnectivity);
vtkm::worklet::DispatcherMapField<MortonNeighbor, DeviceAdapter>(MortonNeighbor())
.Invoke(faceMortonCodes,
vtkm::exec::ExecutionWholeArray<vtkm::Vec<vtkm::Id, 3>>(cellFaceId),
conn,
shapes,
shapeOffsets,
faceConnectivity);
vtkm::Float64 time = timer.GetElapsedTime();
Logger::GetInstance()->AddLogData("gen_face_conn", time);
}
template <typename ShapeHandleType, typename OffsetsHandleType, typename ConnHandleType>
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Vec<Id, 4>> ExtractExternalFaces(
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 3>>
cellFaceId, // Map of cell, face, and connecting cell
vtkm::cont::ArrayHandle<vtkm::Id>
faceConnectivity, // -1 if the face does not connect to any other face
const ShapeHandleType& shapes,
const ConnHandleType& conn,
const OffsetsHandleType& shapeOffsets)
{
vtkm::cont::Timer<DeviceAdapter> timer;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 3>> externalFacePairs;
vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::CopyIf(
cellFaceId, faceConnectivity, externalFacePairs, IsExternal());
// We need to count the number of triangle per external face
// If it is a single cell type and it is a tet or hex, this is a special case
// i.e., we do not need to calculate it. TODO
// Otherwise, we need to check to see if the face is a quad or triangle
vtkm::Id numExternalFaces = externalFacePairs.GetNumberOfValues();
vtkm::cont::ArrayHandle<vtkm::Id> trianglesPerExternalFace;
trianglesPerExternalFace.PrepareForOutput(numExternalFaces, DeviceAdapter());
vtkm::worklet::DispatcherMapField<CountExternalTriangles, DeviceAdapter>(
CountExternalTriangles())
.Invoke(externalFacePairs, shapes, trianglesPerExternalFace);
vtkm::cont::ArrayHandle<vtkm::Id> externalTriangleOffsets;
vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::ScanExclusive(trianglesPerExternalFace,
externalTriangleOffsets);
vtkm::Id totalExternalTriangles;
totalExternalTriangles = vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::Reduce(
trianglesPerExternalFace, vtkm::Id(0));
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> externalTriangles;
externalTriangles.PrepareForOutput(totalExternalTriangles, DeviceAdapter());
//count the number triangles in the external faces
vtkm::worklet::DispatcherMapField<ExternalTriangles, DeviceAdapter>(ExternalTriangles())
.Invoke(
externalFacePairs, shapes, shapeOffsets, conn, externalTriangles, externalTriangleOffsets);
vtkm::Float64 time = timer.GetElapsedTime();
Logger::GetInstance()->AddLogData("external_faces", time);
return externalTriangles;
}
vtkm::cont::ArrayHandle<vtkm::Id> FaceConnectivity;
vtkm::cont::ArrayHandle<vtkm::Id> FaceOffsets;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> OutsideTriangles;
};
}
}
} //namespace vtkm::rendering::raytracing
#endif

@ -0,0 +1,803 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_rendering_raytracing_MeshConnectivityStructures_h
#define vtk_m_rendering_raytracing_MeshConnectivityStructures_h
#include <sstream>
#include <vtkm/CellShape.h>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/rendering/raytracing/BoundingVolumeHierarchy.h>
#include <vtkm/rendering/raytracing/Logger.h>
#include <vtkm/rendering/raytracing/MeshConnectivityBuilder.h>
#include <vtkm/rendering/raytracing/Ray.h>
#include <vtkm/rendering/raytracing/TriangleIntersector.h>
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
// MeshConnectivityStrucutures:
// Policy classes for different types of meshes. Each implemented class
// Must implement GetConnetingCell( indexOfCurrentCell, face) that returns
// the index of the cell that connects to the "face" of the current cell.
// Each policy should have a copy constructor to facilitate clean passing
// to worklets (i.e., initialize execution portals if needed).
//
// Primary template for MeshConnExec Object
//
template <typename MeshType, typename Device>
class MeshConnExec
{
};
class UnstructuredMeshConn
{
public:
typedef vtkm::cont::ArrayHandle<vtkm::Id> IdHandle;
typedef vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> Id4Handle;
typedef vtkm::cont::ArrayHandle<vtkm::UInt8> UCharHandle;
// Control Environment Handles
// FaceConn
IdHandle FaceConnectivity;
IdHandle FaceOffsets;
//Cell Set
IdHandle CellConn;
IdHandle CellOffsets;
UCharHandle Shapes;
// Mesh Boundry
Id4Handle ExternalTriangles;
LinearBVH Bvh;
// Restrict the coordinates to the types that be for unstructured meshes
DynamicArrayHandleExplicitCoordinateSystem Coordinates;
vtkm::Bounds CoordinateBounds;
vtkm::cont::CellSetExplicit<> Cellset;
vtkm::cont::CoordinateSystem Coords;
protected:
bool IsConstructed;
private:
VTKM_CONT
UnstructuredMeshConn(){};
public:
VTKM_CONT
UnstructuredMeshConn(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords)
: IsConstructed(false)
{
Coords = coords;
vtkm::cont::DynamicArrayHandleCoordinateSystem dynamicCoordsHandle = coords.GetData();
//
// Reset the type lists to only contain the coordinate systemss of an
// unstructured cell set.
//
Coordinates = dynamicCoordsHandle.ResetTypeList(ExplicitCoordinatesType())
.ResetStorageList(StorageListTagExplicitCoordinateSystem());
if (!cellset.IsSameType(vtkm::cont::CellSetExplicit<>()))
{
throw vtkm::cont::ErrorBadValue(
"Unstructured Mesh Connecitity Error: not an explicit cell set!");
}
Cellset = cellset.Cast<vtkm::cont::CellSetExplicit<>>();
//
// Grab the cell arrays
//
CellConn =
Cellset.GetConnectivityArray(vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
CellOffsets =
Cellset.GetIndexOffsetArray(vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
Shapes =
Cellset.GetShapesArray(vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
}
//----------------------------------------------------------------------------
template <typename T>
VTKM_CONT UnstructuredMeshConn(const T& other)
: FaceConnectivity(other.FaceConnectivity)
, FaceOffsets(other.FaceOffsets)
, CellConn(other.CellConn)
, CellOffsets(other.CellOffsets)
, Shapes(other.Shapes)
, ExternalTriangles(other.ExternalTriangles)
, Bvh(other.Bvh)
, Coordinates(other.Coordinates)
, CoordinateBounds(other.CoordinateBounds)
, Cellset(other.Cellset)
, Coords(other.Coords)
, IsConstructed(other.IsConstructed)
{
}
//----------------------------------------------------------------------------
template <typename Device>
VTKM_CONT void Construct(Device)
{
Logger* logger = Logger::GetInstance();
logger->OpenLogEntry("mesh_conn_construction");
vtkm::cont::Timer<Device> timer;
if (!IsConstructed)
{
CoordinateBounds = Coords.GetBounds();
MeshConnectivityBuilder<Device> connBuilder;
//
// Build the face-to-face connectivity
//
connBuilder.BuildConnectivity(Cellset, Coordinates, CoordinateBounds);
//
// Initialize all of the array handles
//
FaceConnectivity = connBuilder.GetFaceConnectivity();
FaceOffsets = connBuilder.GetFaceOffsets();
ExternalTriangles = connBuilder.GetExternalTriangles();
//
// Build BVH on external triangles
//
Bvh.SetData(Coords.GetData(), ExternalTriangles);
Bvh.ConstructOnDevice(Device());
IsConstructed = true;
}
vtkm::Float64 time = timer.GetElapsedTime();
logger->CloseLogEntry(time);
}
//----------------------------------------------------------------------------
template <typename T, typename Device>
VTKM_CONT void FindEntry(Ray<T>& rays, Device)
{
if (!IsConstructed)
{
throw vtkm::cont::ErrorBadValue(
"Unstructured Mesh Connecitity Error: FindEntry called before Construct");
}
TriangleIntersector<Device, TriLeafIntersector<WaterTight<T>>> intersector;
bool getCellIndex = true;
intersector.runHitOnly(rays, Bvh, Coordinates, getCellIndex);
}
//----------------------------------------------------------------------------
VTKM_CONT
vtkm::Id GetNumberOfCells() { return this->Shapes.GetPortalConstControl().GetNumberOfValues(); }
//----------------------------------------------------------------------------
// Control Environment Methods
//----------------------------------------------------------------------------
VTKM_CONT
Id4Handle GetExternalTriangles() { return ExternalTriangles; }
//----------------------------------------------------------------------------
VTKM_CONT
DynamicArrayHandleExplicitCoordinateSystem GetCoordinates() { return Coordinates; }
//----------------------------------------------------------------------------
template <typename Device>
VTKM_CONT vtkm::Bounds GetCoordinateBounds(Device)
{
CoordinateBounds = Coords.GetBounds();
return CoordinateBounds;
}
//----------------------------------------------------------------------------
VTKM_CONT
bool GetIsConstructed() { return IsConstructed; }
}; //Unstructure mesh conn
template <typename Device>
class MeshConnExec<UnstructuredMeshConn, Device>
{
protected:
typedef typename vtkm::cont::ArrayHandle<vtkm::Id> IdHandle;
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> Id4Handle;
typedef typename vtkm::cont::ArrayHandle<vtkm::UInt8> UCharHandle;
typedef typename IdHandle::ExecutionTypes<Device>::PortalConst IdConstPortal;
typedef typename UCharHandle::ExecutionTypes<Device>::PortalConst UCharConstPortal;
// Constant Portals for the execution Environment
//FaceConn
IdConstPortal FaceConnPortal;
IdConstPortal FaceOffsetsPortal;
//Cell Set
IdConstPortal CellConnPortal;
IdConstPortal CellOffsetsPortal;
UCharConstPortal ShapesPortal;
private:
VTKM_CONT
MeshConnExec(){};
public:
VTKM_CONT
MeshConnExec(UnstructuredMeshConn& conn)
: FaceConnPortal(conn.FaceConnectivity.PrepareForInput(Device()))
, FaceOffsetsPortal(conn.FaceOffsets.PrepareForInput(Device()))
, CellConnPortal(conn.CellConn.PrepareForInput(Device()))
, CellOffsetsPortal(conn.CellOffsets.PrepareForInput(Device()))
, ShapesPortal(conn.Shapes.PrepareForInput(Device()))
{
if (!conn.GetIsConstructed())
{
throw vtkm::cont::ErrorBadValue(
"Unstructured Mesh Connecitity Error: GetExecObj called before Construct");
}
}
//----------------------------------------------------------------------------
template <typename T>
VTKM_CONT MeshConnExec(const T& other)
: FaceConnPortal(other.FaceConnPortal)
, FaceOffsetsPortal(other.FaceConnPortal)
, CellConnPortal(other.CellConnPortal)
, CellOffsetsPortal(other.CellOffsetsPortal)
, ShapesPortal(other.ShapesPortal)
{
}
//----------------------------------------------------------------------------
// Execution Environment Methods
//----------------------------------------------------------------------------
VTKM_EXEC
inline vtkm::Id GetConnectingCell(const vtkm::Id& cellId, const vtkm::Id& face) const
{
BOUNDS_CHECK(FaceOffsetsPortal, cellId);
vtkm::Id cellStartIndex = FaceOffsetsPortal.Get(cellId);
BOUNDS_CHECK(FaceConnPortal, cellStartIndex + face);
return FaceConnPortal.Get(cellStartIndex + face);
}
//----------------------------------------------------------------------------
VTKM_EXEC
inline vtkm::Int32 GetCellIndices(vtkm::Id cellIndices[8], const vtkm::Id& cellId) const
{
const vtkm::Int32 shapeId = static_cast<vtkm::Int32>(ShapesPortal.Get(cellId));
const vtkm::Int32 numIndices = FaceLookUp[CellTypeLookUp[shapeId]][2];
BOUNDS_CHECK(CellOffsetsPortal, cellId);
const vtkm::Id cellOffset = CellOffsetsPortal.Get(cellId);
for (vtkm::Int32 i = 0; i < numIndices; ++i)
{
BOUNDS_CHECK(CellConnPortal, cellOffset + i);
cellIndices[i] = CellConnPortal.Get(cellOffset + i);
}
return numIndices;
}
//----------------------------------------------------------------------------
VTKM_EXEC
inline vtkm::UInt8 GetCellShape(const vtkm::Id& cellId) const
{
BOUNDS_CHECK(ShapesPortal, cellId)
return ShapesPortal.Get(cellId);
}
}; //Unstructure mesh conn exec
// Specialized version for unstructured meshes consisting of
// a single type of cell.
class UnstructuredMeshConnSingleType
{
public:
typedef vtkm::cont::ArrayHandle<vtkm::Id> IdHandle;
typedef vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> Id4Handle;
typedef vtkm::cont::ArrayHandleCounting<vtkm::Id> CountingHandle;
typedef vtkm::cont::ArrayHandleConstant<vtkm::UInt8> ShapesHandle;
typedef vtkm::cont::ArrayHandleConstant<vtkm::IdComponent> NumIndicesHandle;
// Control Environment Handles
IdHandle FaceConnectivity;
CountingHandle CellOffsets;
IdHandle CellConnectivity;
// Mesh Boundry
LinearBVH Bvh;
Id4Handle ExternalTriangles;
// Restrict the coordinates to the types that be for unstructured meshes
DynamicArrayHandleExplicitCoordinateSystem Coordinates;
vtkm::Bounds CoordinateBounds;
vtkm::cont::CoordinateSystem Coords;
vtkm::cont::CellSetSingleType<> Cellset;
vtkm::Int32 ShapeId;
vtkm::Int32 NumIndices;
vtkm::Int32 NumFaces;
protected:
bool IsConstructed;
private:
VTKM_CONT
UnstructuredMeshConnSingleType() {}
public:
VTKM_CONT
UnstructuredMeshConnSingleType(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords)
: IsConstructed(false)
{
Coords = coords;
vtkm::cont::DynamicArrayHandleCoordinateSystem dynamicCoordsHandle = coords.GetData();
//
// Reset the type lists to only contain the coordinate systemss of an
// unstructured cell set.
//
Coordinates = dynamicCoordsHandle.ResetTypeList(ExplicitCoordinatesType())
.ResetStorageList(StorageListTagExplicitCoordinateSystem());
if (!cellset.IsSameType(vtkm::cont::CellSetSingleType<>()))
{
throw vtkm::cont::ErrorBadValue(
"Unstructured Mesh Connecitity Single type Error: not an single type cell set!");
}
Cellset = cellset.Cast<vtkm::cont::CellSetSingleType<>>();
CellConnectivity =
Cellset.GetConnectivityArray(vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
vtkm::cont::ArrayHandleConstant<vtkm::UInt8> shapes =
Cellset.GetShapesArray(vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
ShapeId = shapes.GetPortalConstControl().Get(0);
NumIndices = FaceLookUp[CellTypeLookUp[ShapeId]][2];
if (NumIndices == 0)
{
std::stringstream message;
message << "Unstructured Mesh Connecitity Single type Error: unsupported cell type: ";
message << ShapeId;
throw vtkm::cont::ErrorBadValue(message.str());
}
vtkm::Id start = 0;
NumFaces = FaceLookUp[CellTypeLookUp[ShapeId]][1];
vtkm::Id numCells = CellConnectivity.GetPortalConstControl().GetNumberOfValues();
CellOffsets = vtkm::cont::make_ArrayHandleCounting<vtkm::Id>(start, NumIndices, numCells);
//
// Initialize all of the array portals
//
}
template <typename T>
VTKM_CONT UnstructuredMeshConnSingleType(const T& other)
: FaceConnectivity(other.FaceConnectivity)
, CellOffsets(other.CellOffsets)
, CellConnectivity(other.CellConnectivity)
, Bvh(other.Bvh)
, ExternalTriangles(other.ExternalTriangles)
, Coordinates(other.Coordinates)
, CoordinateBounds(other.CoordinateBounds)
, Coords(other.coords)
, Cellset(other.Cellset)
, ShapeId(other.ShapeId)
, NumIndices(other.NumIndices)
, NumFaces(other.NumFaces)
, IsConstructed(other.IsConstructed)
{
}
//----------------------------------------------------------------------------
template <typename Device>
VTKM_CONT void Construct(Device)
{
Logger* logger = Logger::GetInstance();
logger->OpenLogEntry("mesh_conn_construction");
vtkm::cont::Timer<Device> timer;
if (!IsConstructed)
{
CoordinateBounds = Coords.GetBounds();
MeshConnectivityBuilder<Device> connBuilder;
//
// Build the face-to-face connectivity
//
connBuilder.BuildConnectivity(Cellset, Coordinates, CoordinateBounds);
//
// Initialize all of the array handles
//
FaceConnectivity = connBuilder.GetFaceConnectivity();
ExternalTriangles = connBuilder.GetExternalTriangles();
//
// Build BVH on external triangles
//
Bvh.SetData(Coords.GetData(), ExternalTriangles);
Bvh.ConstructOnDevice(Device());
IsConstructed = true;
}
vtkm::Float64 time = timer.GetElapsedTime();
logger->CloseLogEntry(time);
}
//----------------------------------------------------------------------------
template <typename T, typename Device>
VTKM_CONT void FindEntry(Ray<T>& rays, Device)
{
if (!IsConstructed)
{
throw vtkm::cont::ErrorBadValue(
"Unstructured Mesh Connecitity Single Error: FindEntry called before Construct");
}
TriangleIntersector<Device, TriLeafIntersector<WaterTight<T>>> intersector;
bool getCellIndex = true;
intersector.runHitOnly(rays, Bvh, Coordinates, getCellIndex);
}
//----------------------------------------------------------------------------
VTKM_CONT
vtkm::Id GetNumberOfCells() { return this->Cellset.GetNumberOfCells(); }
//----------------------------------------------------------------------------
VTKM_CONT
Id4Handle GetExternalTriangles() { return ExternalTriangles; }
//----------------------------------------------------------------------------
VTKM_CONT
DynamicArrayHandleExplicitCoordinateSystem GetCoordinates() { return Coordinates; }
//----------------------------------------------------------------------------
template <typename Device>
VTKM_CONT vtkm::Bounds GetCoordinateBounds(Device)
{
CoordinateBounds = Coords.GetBounds();
return CoordinateBounds;
}
//----------------------------------------------------------------------------
VTKM_CONT
bool GetIsConstructed() { return IsConstructed; }
}; //UnstructuredMeshConn Single Type
template <typename Device>
class MeshConnExec<UnstructuredMeshConnSingleType, Device>
{
protected:
typedef typename vtkm::cont::ArrayHandle<vtkm::Id> IdHandle;
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> Id4Handle;
typedef typename vtkm::cont::ArrayHandleCounting<vtkm::Id> CountingHandle;
typedef typename vtkm::cont::ArrayHandleConstant<vtkm::UInt8> ShapesHandle;
typedef typename IdHandle::ExecutionTypes<Device>::PortalConst IdConstPortal;
typedef typename CountingHandle::ExecutionTypes<Device>::PortalConst CountingPortal;
typedef typename vtkm::cont::ArrayHandleConstant<vtkm::IdComponent> NumIndicesHandle;
// Constant Portals for the execution Environment
IdConstPortal FaceConnPortal;
IdConstPortal CellConnectivityPortal;
CountingPortal CellOffsetsPortal;
vtkm::Int32 ShapeId;
vtkm::Int32 NumIndices;
vtkm::Int32 NumFaces;
private:
VTKM_CONT
MeshConnExec() {}
public:
VTKM_CONT
MeshConnExec(UnstructuredMeshConnSingleType& conn)
: FaceConnPortal(conn.FaceConnectivity.PrepareForInput(Device()))
, CellConnectivityPortal(conn.CellConnectivity.PrepareForInput(Device()))
, CellOffsetsPortal(conn.CellOffsets.PrepareForInput(Device()))
, ShapeId(conn.ShapeId)
, NumIndices(conn.NumIndices)
, NumFaces(conn.NumFaces)
{
if (!conn.GetIsConstructed())
{
throw vtkm::cont::ErrorBadValue(
"Unstructured Mesh Connecitity Single Error: GetExecObj called before Construct");
}
}
template <typename T>
VTKM_CONT MeshConnExec(const T& other)
: FaceConnPortal(other.FaceConnPortal)
, CellOffsetsPortal(other.CellOffsetsPortal)
, CellConnectivityPortal(other.CellConnectivityPortal)
, ShapeId(other.ShapeId)
, NumIndices(other.NumIndices)
, NumFaces(other.NumFaces)
{
}
//----------------------------------------------------------------------------
// Execution Environment Methods
//----------------------------------------------------------------------------
VTKM_EXEC
inline vtkm::Id GetConnectingCell(const vtkm::Id& cellId, const vtkm::Id& face) const
{
BOUNDS_CHECK(CellOffsetsPortal, cellId);
vtkm::Id cellStartIndex = cellId * NumFaces;
BOUNDS_CHECK(FaceConnPortal, cellStartIndex + face);
return FaceConnPortal.Get(cellStartIndex + face);
}
VTKM_EXEC
inline vtkm::Int32 GetCellIndices(vtkm::Id cellIndices[8], const vtkm::Id& cellId) const
{
BOUNDS_CHECK(CellOffsetsPortal, cellId);
const vtkm::Id cellOffset = CellOffsetsPortal.Get(cellId);
for (vtkm::Int32 i = 0; i < NumIndices; ++i)
{
BOUNDS_CHECK(CellConnectivityPortal, cellOffset + i);
cellIndices[i] = CellConnectivityPortal.Get(cellOffset + i);
}
return NumIndices;
}
//----------------------------------------------------------------------------
VTKM_EXEC
inline vtkm::UInt8 GetCellShape(const vtkm::Id& vtkmNotUsed(cellId)) const
{
return vtkm::UInt8(ShapeId);
}
}; //MeshConn Single type specialization
class StructuredMeshConn
{
public:
typedef vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> Id4Handle;
vtkm::Id3 CellDims;
vtkm::Id3 PointDims;
DynamicArrayHandleStructuredCoordinateSystem Coordinates;
vtkm::Bounds CoordinateBounds;
vtkm::cont::CoordinateSystem Coords;
vtkm::cont::CellSetStructured<3> Cellset;
// Mesh Boundry
LinearBVH Bvh;
Id4Handle ExternalTriangles;
protected:
bool IsConstructed;
private:
VTKM_CONT
StructuredMeshConn() {}
public:
VTKM_CONT
StructuredMeshConn(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords)
: IsConstructed(false)
{
Coords = coords;
vtkm::cont::DynamicArrayHandleCoordinateSystem dynamicCoordsHandle = coords.GetData();
//
// Reset the type lists to only contain the coordinate systemss of an
// unstructured cell set.
//
Coordinates = dynamicCoordsHandle.ResetTypeList(ExplicitCoordinatesType())
.ResetStorageList(StructuredStorage());
if (!cellset.IsSameType(vtkm::cont::CellSetStructured<3>()))
{
throw vtkm::cont::ErrorBadValue(
"Structured Mesh Connecitity Error: not a Structured<3> cell set!");
}
Cellset = cellset.Cast<vtkm::cont::CellSetStructured<3>>();
PointDims = Cellset.GetPointDimensions();
CellDims = Cellset.GetCellDimensions();
}
template <typename T>
VTKM_CONT StructuredMeshConn(const T& other)
: CellDims(other.CellDims)
, PointDims(other.PointDims)
, Coordinates(other.Coordinates)
, CoordinateBounds(other.CoordinateBounds)
, Coords(other.coords)
, Cellset(other.Cellset)
, Bvh(other.Bvh)
, ExternalTriangles(other.ExternalTriangles)
, IsConstructed(other.IsConstructed)
{
}
//----------------------------------------------------------------------------
template <typename Device>
VTKM_CONT void Construct(Device)
{
Logger* logger = Logger::GetInstance();
logger->OpenLogEntry("mesh_conn_construction");
vtkm::cont::Timer<Device> timer;
if (!IsConstructed)
{
CoordinateBounds = Coords.GetBounds();
MeshConnectivityBuilder<Device> connBuilder;
ExternalTriangles = connBuilder.ExternalTrianglesStructured(Cellset);
//
// Build BVH on external triangles
//
Bvh.SetData(Coords.GetData(), ExternalTriangles);
Bvh.ConstructOnDevice(Device());
IsConstructed = true;
}
vtkm::Float64 time = timer.GetElapsedTime();
logger->CloseLogEntry(time);
}
//----------------------------------------------------------------------------
template <typename T, typename Device>
VTKM_CONT void FindEntry(Ray<T>& rays, Device)
{
if (!IsConstructed)
{
throw vtkm::cont::ErrorBadValue(
"Structured Mesh Connecitity Single Error: FindEntry called before Construct");
}
TriangleIntersector<Device, TriLeafIntersector<WaterTight<T>>> intersector;
bool getCellIndex = true;
intersector.runHitOnly(rays, Bvh, Coordinates, getCellIndex);
}
//----------------------------------------------------------------------------
VTKM_CONT
vtkm::Id GetNumberOfCells() { return this->CellDims[0] * this->CellDims[1] * this->CellDims[2]; }
//----------------------------------------------------------------------------
// Control Environment Methods
//----------------------------------------------------------------------------
VTKM_CONT
Id4Handle GetExternalTriangles() { return ExternalTriangles; }
//----------------------------------------------------------------------------
VTKM_CONT
DynamicArrayHandleStructuredCoordinateSystem GetCoordinates() { return Coordinates; }
//----------------------------------------------------------------------------
template <typename Device>
VTKM_CONT vtkm::Bounds GetCoordinateBounds(Device)
{
CoordinateBounds = Coords.GetBounds();
return CoordinateBounds;
}
//----------------------------------------------------------------------------
VTKM_CONT
bool GetIsConstructed() { return IsConstructed; }
}; //structure mesh conn
template <typename Device>
class MeshConnExec<StructuredMeshConn, Device>
{
protected:
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> Id4Handle;
vtkm::Id3 CellDims;
vtkm::Id3 PointDims;
vtkm::Bounds CoordinateBounds;
private:
VTKM_CONT
MeshConnExec() {}
public:
VTKM_CONT
MeshConnExec(const StructuredMeshConn& other)
: CellDims(other.CellDims)
, PointDims(other.PointDims)
, CoordinateBounds(other.CoordinateBounds)
{
}
template <typename T>
VTKM_CONT MeshConnExec(const T& other)
: CellDims(other.CellDims)
, PointDims(other.PointDims)
, CoordinateBounds(other.CoordinateBounds)
{
}
//----------------------------------------------------------------------------
// Execution Environment Methods
//----------------------------------------------------------------------------
VTKM_EXEC_CONT
inline vtkm::Id GetConnectingCell(const vtkm::Id& cellId, const vtkm::Id& face) const
{
//TODO: there is probably a better way to do this.
vtkm::Id3 logicalCellId;
logicalCellId[0] = cellId % CellDims[0];
logicalCellId[1] = (cellId / CellDims[0]) % CellDims[1];
logicalCellId[2] = cellId / (CellDims[0] * CellDims[1]);
if (face == 0)
logicalCellId[1] -= 1;
if (face == 2)
logicalCellId[1] += 1;
if (face == 1)
logicalCellId[0] += 1;
if (face == 3)
logicalCellId[0] -= 1;
if (face == 4)
logicalCellId[2] -= 1;
if (face == 5)
logicalCellId[2] += 1;
vtkm::Id nextCell =
(logicalCellId[2] * CellDims[1] + logicalCellId[1]) * CellDims[0] + logicalCellId[0];
bool validCell = true;
if (logicalCellId[0] >= CellDims[0])
validCell = false;
if (logicalCellId[1] >= CellDims[1])
validCell = false;
if (logicalCellId[2] >= CellDims[2])
validCell = false;
vtkm::Id minId = vtkm::Min(logicalCellId[0], vtkm::Min(logicalCellId[1], logicalCellId[2]));
if (minId < 0)
validCell = false;
if (!validCell)
nextCell = -1;
return nextCell;
}
//----------------------------------------------------------------------------
VTKM_EXEC_CONT
inline vtkm::Int32 GetCellIndices(vtkm::Id cellIndices[8], const vtkm::Id& cellIndex) const
{
vtkm::Id3 cellId;
cellId[0] = cellIndex % CellDims[0];
cellId[1] = (cellIndex / CellDims[0]) % CellDims[1];
cellId[2] = cellIndex / (CellDims[0] * CellDims[1]);
cellIndices[0] = (cellId[2] * PointDims[1] + cellId[1]) * PointDims[0] + cellId[0];
cellIndices[1] = cellIndices[0] + 1;
cellIndices[2] = cellIndices[1] + PointDims[0];
cellIndices[3] = cellIndices[2] - 1;
cellIndices[4] = cellIndices[0] + PointDims[0] * PointDims[1];
cellIndices[5] = cellIndices[4] + 1;
cellIndices[6] = cellIndices[5] + PointDims[0];
cellIndices[7] = cellIndices[6] - 1;
return 8;
}
//----------------------------------------------------------------------------
VTKM_EXEC_CONT
inline vtkm::Int32 GetCellIndices(vtkm::Id cellIndices[8],
const vtkm::Vec<vtkm::Id, 3>& cellId) const
{
cellIndices[0] = (cellId[2] * PointDims[1] + cellId[1]) * PointDims[0] + cellId[0];
cellIndices[1] = cellIndices[0] + 1;
cellIndices[2] = cellIndices[1] + PointDims[0];
cellIndices[3] = cellIndices[2] - 1;
cellIndices[4] = cellIndices[0] + PointDims[0] * PointDims[1];
cellIndices[5] = cellIndices[4] + 1;
cellIndices[6] = cellIndices[5] + PointDims[0];
cellIndices[7] = cellIndices[6] - 1;
return 8;
}
//----------------------------------------------------------------------------
VTKM_EXEC
inline vtkm::UInt8 GetCellShape(const vtkm::Id& vtkmNotUsed(cellId)) const
{
return vtkm::UInt8(CELL_SHAPE_HEXAHEDRON);
}
}; //Unstructure mesh conn
}
}
} //namespace vtkm::rendering::raytracing
#endif

@ -0,0 +1,301 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_rendering_raytracing_MortonCodes_h
#define vtk_m_rendering_raytracing_MortonCodes_h
#include <vtkm/VectorAnalysis.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/rendering/raytracing/CellTables.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/WorkletMapTopology.h>
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
//Note: if this takes a long time. we could use a lookup table
//expands 10-bit unsigned int into 30 bits
VTKM_EXEC inline vtkm::UInt32 ExpandBits32(vtkm::UInt32 x32)
{
x32 = (x32 | (x32 << 16)) & 0x030000FF;
x32 = (x32 | (x32 << 8)) & 0x0300F00F;
x32 = (x32 | (x32 << 4)) & 0x030C30C3;
x32 = (x32 | (x32 << 2)) & 0x09249249;
return x32;
}
VTKM_EXEC inline vtkm::UInt64 ExpandBits64(vtkm::UInt32 x)
{
vtkm::UInt64 x64 = x & 0x1FFFFF;
x64 = (x64 | x64 << 32) & 0x1F00000000FFFF;
x64 = (x64 | x64 << 16) & 0x1F0000FF0000FF;
x64 = (x64 | x64 << 8) & 0x100F00F00F00F00F;
x64 = (x64 | x64 << 4) & 0x10c30c30c30c30c3;
x64 = (x64 | x64 << 2) & 0x1249249249249249;
return x64;
}
//Returns 30 bit morton code for coordinates for
//coordinates in the unit cude
VTKM_EXEC inline vtkm::UInt32 Morton3D(vtkm::Float32& x, vtkm::Float32& y, vtkm::Float32& z)
{
//take the first 10 bits
x = vtkm::Min(vtkm::Max(x * 1024.0f, 0.0f), 1023.0f);
y = vtkm::Min(vtkm::Max(y * 1024.0f, 0.0f), 1023.0f);
z = vtkm::Min(vtkm::Max(z * 1024.0f, 0.0f), 1023.0f);
//expand the 10 bits to 30
vtkm::UInt32 xx = ExpandBits32((vtkm::UInt32)x);
vtkm::UInt32 yy = ExpandBits32((vtkm::UInt32)y);
vtkm::UInt32 zz = ExpandBits32((vtkm::UInt32)z);
//interleave coordinates
return (zz << 2 | yy << 1 | xx);
}
//Returns 30 bit morton code for coordinates for
//coordinates in the unit cude
VTKM_EXEC inline vtkm::UInt64 Morton3D64(vtkm::Float32& x, vtkm::Float32& y, vtkm::Float32& z)
{
//take the first 21 bits
x = vtkm::Min(vtkm::Max(x * 2097152.0f, 0.0f), 2097151.0f);
y = vtkm::Min(vtkm::Max(y * 2097152.0f, 0.0f), 2097151.0f);
z = vtkm::Min(vtkm::Max(z * 2097152.0f, 0.0f), 2097151.0f);
//expand the 10 bits to 30
vtkm::UInt64 xx = ExpandBits64((vtkm::UInt32)x);
vtkm::UInt64 yy = ExpandBits64((vtkm::UInt32)y);
vtkm::UInt64 zz = ExpandBits64((vtkm::UInt32)z);
//interleave coordinates
return (zz << 2 | yy << 1 | xx);
}
class MortonCodeFace : public vtkm::worklet::WorkletMapPointToCell
{
private:
// (1.f / dx),(1.f / dy), (1.f, / dz)
vtkm::Vec<vtkm::Float32, 3> InverseExtent;
vtkm::Vec<vtkm::Float32, 3> MinCoordinate;
VTKM_EXEC inline void Normalize(vtkm::Vec<vtkm::Float32, 3>& point) const
{
point = (point - MinCoordinate) * InverseExtent;
}
VTKM_EXEC inline void Sort4(vtkm::Vec<vtkm::Id, 4>& indices) const
{
if (indices[0] < indices[1])
{
vtkm::Id temp = indices[1];
indices[1] = indices[0];
indices[0] = temp;
}
if (indices[2] < indices[3])
{
vtkm::Id temp = indices[3];
indices[3] = indices[2];
indices[2] = temp;
}
if (indices[0] < indices[2])
{
vtkm::Id temp = indices[2];
indices[2] = indices[0];
indices[0] = temp;
}
if (indices[1] < indices[3])
{
vtkm::Id temp = indices[3];
indices[3] = indices[1];
indices[1] = temp;
}
if (indices[1] < indices[2])
{
vtkm::Id temp = indices[2];
indices[2] = indices[1];
indices[1] = temp;
}
}
public:
VTKM_CONT
MortonCodeFace(const vtkm::Vec<vtkm::Float32, 3>& inverseExtent,
const vtkm::Vec<vtkm::Float32, 3>& minCoordinate)
: InverseExtent(inverseExtent)
, MinCoordinate(minCoordinate)
{
}
typedef void ControlSignature(CellSetIn cellset,
WholeArrayIn<>,
FieldInTo<>,
WholeArrayOut<>,
WholeArrayOut<>);
typedef void ExecutionSignature(CellShape, FromIndices, WorkIndex, _2, _3, _4, _5);
template <typename CellShape,
typename CellNodeVecType,
typename PointPortalType,
typename MortonPortalType,
typename CellFaceIdsPortalType>
VTKM_EXEC inline void operator()(const CellShape& cellShape,
const CellNodeVecType& cellIndices,
const vtkm::Id& cellId,
const PointPortalType& points,
const vtkm::Id& offset,
MortonPortalType& mortonCodes,
CellFaceIdsPortalType& cellFaceIds) const
{
vtkm::Int32 faceCount;
vtkm::Int32 tableOffset;
// suppress some unused variables warnings
(void)(CellTypeLookUp);
(void)(ZooTable);
(void)(ZooLookUp);
if (cellShape.Id == vtkm::CELL_SHAPE_TETRA)
{
faceCount = FaceLookUp[1][1];
tableOffset = FaceLookUp[1][0];
}
else if (cellShape.Id == vtkm::CELL_SHAPE_HEXAHEDRON)
{
faceCount = FaceLookUp[0][1];
tableOffset = FaceLookUp[0][0];
}
else if (cellShape.Id == vtkm::CELL_SHAPE_WEDGE)
{
faceCount = FaceLookUp[2][1];
tableOffset = FaceLookUp[2][0];
}
else if (cellShape.Id == vtkm::CELL_SHAPE_PYRAMID)
{
faceCount = FaceLookUp[3][1];
tableOffset = FaceLookUp[3][0];
}
else
{
printf("Unknown shape type %d\n", (int)cellShape.Id);
return;
}
//calc the morton code at the center of each face
for (vtkm::Int32 i = 0; i < faceCount; ++i)
{
vtkm::Vec<vtkm::Float32, 3> center;
vtkm::UInt32 code;
vtkm::Vec<vtkm::Id, 3> cellFace;
cellFace[0] = cellId;
// We must be sure that this calulation is the same for all faces. If we didn't
// then it is possible for the same face to end up in multiple morton "buckets" due to
// the wonders of floating point math. This is bad. If we calculate in the same order
// for all faces, then at worst, two different faces can enter the same bucket, which
// we currently check for.
vtkm::Vec<vtkm::Id, 4> faceIndices;
faceIndices[3] = -1;
const vtkm::Id indiceCount =
ShapesFaceList[tableOffset + i][0]; //Number of indices this face has
for (vtkm::Int32 j = 1; j <= indiceCount; j++)
{
faceIndices[j - 1] = cellIndices[ShapesFaceList[tableOffset + i][j]];
}
//sort the indices in descending order
Sort4(faceIndices);
vtkm::Int32 count = 1;
BOUNDS_CHECK(points, faceIndices[0]);
center = points.Get(faceIndices[0]);
for (int idx = 1; idx < indiceCount; ++idx)
{
BOUNDS_CHECK(points, faceIndices[idx]);
center = center + points.Get(faceIndices[idx]);
count++;
}
//TODO: we could make this a recipical, but this is not a bottleneck.
center[0] = center[0] / vtkm::Float32(count + 1);
center[1] = center[1] / vtkm::Float32(count + 1);
center[2] = center[2] / vtkm::Float32(count + 1);
Normalize(center);
code = Morton3D(center[0], center[1], center[2]);
BOUNDS_CHECK(mortonCodes, offset + i);
mortonCodes.Set(offset + i, code);
cellFace[1] = i;
cellFace[2] = -1; //Need to initialize this for the next step
BOUNDS_CHECK(cellFaceIds, offset + i);
cellFaceIds.Set(offset + i, cellFace);
}
}
}; // class MortonCodeFace
class MortonCodeAABB : public vtkm::worklet::WorkletMapField
{
private:
// (1.f / dx),(1.f / dy), (1.f, / dz)
vtkm::Vec<vtkm::Float32, 3> InverseExtent;
vtkm::Vec<vtkm::Float32, 3> MinCoordinate;
public:
VTKM_CONT
MortonCodeAABB(const vtkm::Vec<vtkm::Float32, 3>& inverseExtent,
const vtkm::Vec<vtkm::Float32, 3>& minCoordinate)
: InverseExtent(inverseExtent)
, MinCoordinate(minCoordinate)
{
}
typedef void
ControlSignature(FieldIn<>, FieldIn<>, FieldIn<>, FieldIn<>, FieldIn<>, FieldIn<>, FieldOut<>);
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6, _7);
typedef _7 InputDomain;
VTKM_EXEC
void operator()(const vtkm::Float32& xmin,
const vtkm::Float32& ymin,
const vtkm::Float32& zmin,
const vtkm::Float32& xmax,
const vtkm::Float32& ymax,
const vtkm::Float32& zmax,
vtkm::UInt32& mortonCode) const
{
vtkm::Vec<vtkm::Float32, 3> direction(xmax - xmin, ymax - ymin, zmax - zmin);
vtkm::Float32 halfDistance = sqrtf(vtkm::dot(direction, direction)) * 0.5f;
vtkm::Normalize(direction);
vtkm::Float32 centroidx = xmin + halfDistance * direction[0] - MinCoordinate[0];
vtkm::Float32 centroidy = ymin + halfDistance * direction[1] - MinCoordinate[1];
vtkm::Float32 centroidz = zmin + halfDistance * direction[2] - MinCoordinate[2];
//normalize the centroid tp 10 bits
centroidx *= InverseExtent[0];
centroidy *= InverseExtent[1];
centroidz *= InverseExtent[2];
mortonCode = Morton3D(centroidx, centroidy, centroidz);
}
}; // class MortonCodeAABB
}
}
} //namespace vtkm::rendering::raytracing
#endif

@ -19,9 +19,25 @@
//============================================================================
#ifndef vtk_m_rendering_raytracing_Ray_h
#define vtk_m_rendering_raytracing_Ray_h
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleCompositeVector.h>
#include <vtkm/cont/DeviceAdapter.h>
#include <vtkm/rendering/raytracing/ChannelBuffer.h>
#include <vtkm/rendering/raytracing/Worklets.h>
#include <vector>
#define RAY_ACTIVE 0
#define RAY_COMPLETE 1
#define RAY_TERMINATED 2
#define RAY_EXITED_MESH 3
#define RAY_EXITED_DOMAIN 4
#define RAY_LOST 5
#define RAY_ABANDONED 6
#define RAY_TUG_EPSILON 0.001
namespace vtkm
{
namespace rendering
@ -29,66 +45,73 @@ namespace rendering
namespace raytracing
{
class RayBase
template <typename Precision>
class Ray
{
public:
RayBase() {}
protected:
bool IntersectionDataEnabled;
virtual ~RayBase();
virtual void resize(const vtkm::Int32 vtkmNotUsed(newSize)) {}
};
template <typename DeviceAdapter>
class Ray : public RayBase
{
public:
// composite vectors to hold array handles
vtkm::cont::ArrayHandleCompositeVectorType<vtkm::cont::ArrayHandle<vtkm::Float32>,
vtkm::cont::ArrayHandle<vtkm::Float32>,
vtkm::cont::ArrayHandle<vtkm::Float32>>::type
Intersection;
typename //tell the compiler we have a dependent type
vtkm::cont::ArrayHandleCompositeVectorType<vtkm::cont::ArrayHandle<Precision>,
vtkm::cont::ArrayHandle<Precision>,
vtkm::cont::ArrayHandle<Precision>>::type
Intersection;
vtkm::cont::ArrayHandleCompositeVectorType<vtkm::cont::ArrayHandle<vtkm::Float32>,
vtkm::cont::ArrayHandle<vtkm::Float32>,
vtkm::cont::ArrayHandle<vtkm::Float32>>::type Normal;
typename //tell the compiler we have a dependent type
vtkm::cont::ArrayHandleCompositeVectorType<vtkm::cont::ArrayHandle<Precision>,
vtkm::cont::ArrayHandle<Precision>,
vtkm::cont::ArrayHandle<Precision>>::type Normal;
vtkm::cont::ArrayHandleCompositeVectorType<vtkm::cont::ArrayHandle<vtkm::Float32>,
vtkm::cont::ArrayHandle<vtkm::Float32>,
vtkm::cont::ArrayHandle<vtkm::Float32>>::type Origin;
typename //tell the compiler we have a dependent type
vtkm::cont::ArrayHandleCompositeVectorType<vtkm::cont::ArrayHandle<Precision>,
vtkm::cont::ArrayHandle<Precision>,
vtkm::cont::ArrayHandle<Precision>>::type Origin;
vtkm::cont::ArrayHandleCompositeVectorType<vtkm::cont::ArrayHandle<vtkm::Float32>,
vtkm::cont::ArrayHandle<vtkm::Float32>,
vtkm::cont::ArrayHandle<vtkm::Float32>>::type Dir;
typename //tell the compiler we have a dependent type
vtkm::cont::ArrayHandleCompositeVectorType<vtkm::cont::ArrayHandle<Precision>,
vtkm::cont::ArrayHandle<Precision>,
vtkm::cont::ArrayHandle<Precision>>::type Dir;
vtkm::cont::ArrayHandle<vtkm::Float32> IntersectionX; //ray Normal
vtkm::cont::ArrayHandle<vtkm::Float32> IntersectionY;
vtkm::cont::ArrayHandle<vtkm::Float32> IntersectionZ;
vtkm::cont::ArrayHandle<Precision> IntersectionX; //ray Intersection
vtkm::cont::ArrayHandle<Precision> IntersectionY;
vtkm::cont::ArrayHandle<Precision> IntersectionZ;
vtkm::cont::ArrayHandle<vtkm::Float32> NormalX; //ray Normal
vtkm::cont::ArrayHandle<vtkm::Float32> NormalY;
vtkm::cont::ArrayHandle<vtkm::Float32> NormalZ;
vtkm::cont::ArrayHandle<vtkm::Float32> OriginX; //ray Origin
vtkm::cont::ArrayHandle<vtkm::Float32> OriginY;
vtkm::cont::ArrayHandle<vtkm::Float32> OriginZ;
vtkm::cont::ArrayHandle<Precision> OriginX; //ray Origin
vtkm::cont::ArrayHandle<Precision> OriginY;
vtkm::cont::ArrayHandle<Precision> OriginZ;
vtkm::cont::ArrayHandle<vtkm::Float32> DirX; //ray Dir
vtkm::cont::ArrayHandle<vtkm::Float32> DirY;
vtkm::cont::ArrayHandle<vtkm::Float32> DirZ;
vtkm::cont::ArrayHandle<Precision> DirX; //ray Dir
vtkm::cont::ArrayHandle<Precision> DirY;
vtkm::cont::ArrayHandle<Precision> DirZ;
vtkm::cont::ArrayHandle<vtkm::Float32> U; //barycentric coordinates
vtkm::cont::ArrayHandle<vtkm::Float32> V;
vtkm::cont::ArrayHandle<Precision> U; //barycentric coordinates
vtkm::cont::ArrayHandle<Precision> V;
vtkm::cont::ArrayHandle<Precision> NormalX; //ray Normal
vtkm::cont::ArrayHandle<Precision> NormalY;
vtkm::cont::ArrayHandle<Precision> NormalZ;
vtkm::cont::ArrayHandle<Precision> Scalar; //scalar
vtkm::cont::ArrayHandle<vtkm::Float32> Distance; //distance to hit
vtkm::cont::ArrayHandle<vtkm::Float32> Scalar; //scalar
vtkm::cont::ArrayHandle<Precision> Distance; //distance to hit
vtkm::cont::ArrayHandle<vtkm::Id> HitIdx;
vtkm::cont::ArrayHandle<vtkm::Id> PixelIdx;
vtkm::cont::ArrayHandle<Precision> MinDistance; // distance to hit
vtkm::cont::ArrayHandle<Precision> MaxDistance; // distance to hit
vtkm::cont::ArrayHandle<vtkm::UInt8> Status; // 0 = active 1 = miss 2 = lost
std::vector<ChannelBuffer<Precision>> Buffers;
vtkm::Id DebugWidth;
vtkm::Id DebugHeight;
vtkm::Id NumRays;
vtkm::Int32 NumRays;
VTKM_CONT
Ray()
{
IntersectionDataEnabled = false;
NumRays = 0;
vtkm::IdComponent inComp[3];
inComp[0] = 0;
@ -105,34 +128,94 @@ public:
Dir = vtkm::cont::make_ArrayHandleCompositeVector(
DirX, inComp[0], DirY, inComp[1], DirZ, inComp[2]);
ChannelBuffer<Precision> buffer;
buffer.Resize(NumRays);
Buffers.push_back(buffer);
DebugWidth = -1;
DebugHeight = -1;
}
VTKM_CONT
Ray(const vtkm::Int32 size)
template <typename Device>
void EnableIntersectionData(Device)
{
if (IntersectionDataEnabled)
{
return;
}
IntersectionDataEnabled = true;
IntersectionX.PrepareForOutput(NumRays, Device());
IntersectionY.PrepareForOutput(NumRays, Device());
IntersectionZ.PrepareForOutput(NumRays, Device());
U.PrepareForOutput(NumRays, Device());
V.PrepareForOutput(NumRays, Device());
Scalar.PrepareForOutput(NumRays, Device());
NormalX.PrepareForOutput(NumRays, Device());
NormalY.PrepareForOutput(NumRays, Device());
NormalZ.PrepareForOutput(NumRays, Device());
}
void DisableIntersectionData()
{
if (!IntersectionDataEnabled)
{
return;
}
IntersectionDataEnabled = false;
IntersectionX.ReleaseResources();
IntersectionY.ReleaseResources();
IntersectionZ.ReleaseResources();
U.ReleaseResources();
V.ReleaseResources();
Scalar.ReleaseResources();
NormalX.ReleaseResources();
NormalY.ReleaseResources();
NormalZ.ReleaseResources();
}
template <typename Device>
VTKM_CONT Ray(const vtkm::Int32 size, Device, bool enableIntersectionData = false)
{
NumRays = size;
IntersectionX.PrepareForOutput(NumRays, DeviceAdapter());
IntersectionY.PrepareForOutput(NumRays, DeviceAdapter());
IntersectionZ.PrepareForOutput(NumRays, DeviceAdapter());
IntersectionDataEnabled = enableIntersectionData;
NormalX.PrepareForOutput(NumRays, DeviceAdapter());
NormalY.PrepareForOutput(NumRays, DeviceAdapter());
NormalZ.PrepareForOutput(NumRays, DeviceAdapter());
if (IntersectionDataEnabled)
{
IntersectionX.PrepareForOutput(NumRays, Device());
IntersectionY.PrepareForOutput(NumRays, Device());
IntersectionZ.PrepareForOutput(NumRays, Device());
OriginX.PrepareForOutput(NumRays, DeviceAdapter());
OriginY.PrepareForOutput(NumRays, DeviceAdapter());
OriginZ.PrepareForOutput(NumRays, DeviceAdapter());
U.PrepareForOutput(NumRays, Device());
V.PrepareForOutput(NumRays, Device());
DirX.PrepareForOutput(NumRays, DeviceAdapter());
DirY.PrepareForOutput(NumRays, DeviceAdapter());
DirZ.PrepareForOutput(NumRays, DeviceAdapter());
Scalar.PrepareForOutput(NumRays, Device());
U.PrepareForOutput(NumRays, DeviceAdapter());
V.PrepareForOutput(NumRays, DeviceAdapter());
Distance.PrepareForOutput(NumRays, DeviceAdapter());
Scalar.PrepareForOutput(NumRays, DeviceAdapter());
NormalX.PrepareForOutput(NumRays, Device());
NormalY.PrepareForOutput(NumRays, Device());
NormalZ.PrepareForOutput(NumRays, Device());
}
HitIdx.PrepareForOutput(NumRays, DeviceAdapter());
OriginX.PrepareForOutput(NumRays, Device());
OriginY.PrepareForOutput(NumRays, Device());
OriginZ.PrepareForOutput(NumRays, Device());
DirX.PrepareForOutput(NumRays, Device());
DirY.PrepareForOutput(NumRays, Device());
DirZ.PrepareForOutput(NumRays, Device());
Distance.PrepareForOutput(NumRays, Device());
MinDistance.PrepareForOutput(NumRays, Device());
MaxDistance.PrepareForOutput(NumRays, Device());
Status.PrepareForOutput(NumRays, Device());
HitIdx.PrepareForOutput(NumRays, Device());
PixelIdx.PrepareForOutput(NumRays, Device());
vtkm::IdComponent inComp[3];
inComp[0] = 0;
@ -150,106 +233,26 @@ public:
Dir = vtkm::cont::make_ArrayHandleCompositeVector(
DirX, inComp[0], DirY, inComp[1], DirZ, inComp[2]);
ChannelBuffer<Precision> buffer;
buffer.Resize(NumRays, Device());
this->Buffers.push_back(buffer);
DebugWidth = -1;
DebugHeight = -1;
}
VTKM_CONT
virtual void resize(const vtkm::Int32 newSize)
void AddBuffer(const vtkm::Int32 numChannels, const std::string name)
{
if (newSize == NumRays)
return; //nothing to do
NumRays = newSize;
IntersectionX.PrepareForOutput(NumRays, DeviceAdapter());
IntersectionY.PrepareForOutput(NumRays, DeviceAdapter());
IntersectionZ.PrepareForOutput(NumRays, DeviceAdapter());
NormalX.PrepareForOutput(NumRays, DeviceAdapter());
NormalY.PrepareForOutput(NumRays, DeviceAdapter());
NormalZ.PrepareForOutput(NumRays, DeviceAdapter());
OriginX.PrepareForOutput(NumRays, DeviceAdapter());
OriginY.PrepareForOutput(NumRays, DeviceAdapter());
OriginZ.PrepareForOutput(NumRays, DeviceAdapter());
DirX.PrepareForOutput(NumRays, DeviceAdapter());
DirY.PrepareForOutput(NumRays, DeviceAdapter());
DirZ.PrepareForOutput(NumRays, DeviceAdapter());
U.PrepareForOutput(NumRays, DeviceAdapter());
V.PrepareForOutput(NumRays, DeviceAdapter());
Distance.PrepareForOutput(NumRays, DeviceAdapter());
Scalar.PrepareForOutput(NumRays, DeviceAdapter());
HitIdx.PrepareForOutput(NumRays, DeviceAdapter());
}
}; // class ray
template <typename DeviceAdapter>
class VolumeRay : public RayBase
{
public:
vtkm::cont::ArrayHandleCompositeVectorType<vtkm::cont::ArrayHandle<vtkm::Float32>,
vtkm::cont::ArrayHandle<vtkm::Float32>,
vtkm::cont::ArrayHandle<vtkm::Float32>>::type Dir;
vtkm::cont::ArrayHandle<vtkm::Float32> DirX; //ray Dir
vtkm::cont::ArrayHandle<vtkm::Float32> DirY;
vtkm::cont::ArrayHandle<vtkm::Float32> DirZ;
vtkm::cont::ArrayHandle<vtkm::Float32> MinDistance; //distance to hit
vtkm::cont::ArrayHandle<vtkm::Float32> MaxDistance; //distance to hit
vtkm::cont::ArrayHandle<vtkm::Id> HitIndex;
vtkm::Int32 NumRays;
VTKM_CONT
VolumeRay()
{
NumRays = 0;
vtkm::IdComponent inComp[3];
inComp[0] = 0;
inComp[1] = 1;
inComp[2] = 2;
Dir = vtkm::cont::make_ArrayHandleCompositeVector(
DirX, inComp[0], DirY, inComp[1], DirZ, inComp[2]);
}
VTKM_CONT
VolumeRay(const vtkm::Int32 size)
{
NumRays = size;
DirX.PrepareForOutput(NumRays, DeviceAdapter());
DirY.PrepareForOutput(NumRays, DeviceAdapter());
DirZ.PrepareForOutput(NumRays, DeviceAdapter());
MinDistance.PrepareForOutput(NumRays, DeviceAdapter());
MaxDistance.PrepareForOutput(NumRays, DeviceAdapter());
HitIndex.PrepareForOutput(NumRays, DeviceAdapter());
vtkm::IdComponent inComp[3];
inComp[0] = 0;
inComp[1] = 1;
inComp[2] = 2;
Dir = vtkm::cont::make_ArrayHandleCompositeVector(
DirX, inComp[0], DirY, inComp[1], DirZ, inComp[2]);
}
VTKM_CONT
virtual void resize(const vtkm::Int32 newSize)
{
if (newSize == NumRays)
return; //nothing to do
NumRays = newSize;
DirX.PrepareForOutput(NumRays, DeviceAdapter());
DirY.PrepareForOutput(NumRays, DeviceAdapter());
DirZ.PrepareForOutput(NumRays, DeviceAdapter());
MinDistance.PrepareForOutput(NumRays, DeviceAdapter());
MaxDistance.PrepareForOutput(NumRays, DeviceAdapter());
HitIndex.PrepareForOutput(NumRays, DeviceAdapter());
ChannelBuffer<Precision> buffer(numChannels, this->NumRays);
buffer.SetName(name);
this->Buffers.push_back(buffer);
}
friend class RayOperations;
}; // class ray
}
}

@ -0,0 +1,292 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_rendering_raytracing_Ray_Operations_h
#define vtk_m_rendering_raytracing_Ray_Operations_h
#include <vtkm/rendering/raytracing/ChannelBufferOperations.h>
#include <vtkm/rendering/raytracing/Ray.h>
#include <vtkm/rendering/raytracing/Worklets.h>
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
namespace detail
{
class RayStatusFilter : public vtkm::worklet::WorkletMapField
{
public:
VTKM_CONT
RayStatusFilter() {}
typedef void ControlSignature(FieldIn<>, FieldInOut<>);
typedef void ExecutionSignature(_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
} // namespace detail
class RayOperations
{
public:
template <typename Device, typename T>
static void ResetStatus(Ray<T>& rays, vtkm::UInt8 status, Device)
{
vtkm::worklet::DispatcherMapField<MemSet<vtkm::UInt8>, Device>(MemSet<vtkm::UInt8>(status))
.Invoke(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 <typename Device, typename T>
static void UpdateRayStatus(Ray<T>& rays, Device)
{
vtkm::worklet::DispatcherMapField<detail::RayStatusFilter, Device>(detail::RayStatusFilter())
.Invoke(rays.HitIdx, rays.Status);
}
template <typename Device, typename T>
static vtkm::Id RaysInMesh(Ray<T>& rays, Device)
{
vtkm::Vec<UInt8, 2> maskValues;
maskValues[0] = RAY_ACTIVE;
maskValues[1] = RAY_LOST;
vtkm::cont::ArrayHandle<vtkm::UInt8> masks;
vtkm::worklet::DispatcherMapField<ManyMask<vtkm::UInt8, 2>, Device>(
ManyMask<vtkm::UInt8, 2>(maskValues))
.Invoke(rays.Status, masks);
vtkm::cont::ArrayHandleCast<vtkm::Id, vtkm::cont::ArrayHandle<vtkm::UInt8>> castedMasks(masks);
const vtkm::Id initVal = 0;
vtkm::Id count = vtkm::cont::DeviceAdapterAlgorithm<Device>::Reduce(castedMasks, initVal);
return count;
}
template <typename Device, typename T>
static vtkm::Id GetStatusCount(Ray<T>& rays, vtkm::Id status, Device)
{
vtkm::UInt8 statusUInt8;
if (status < 0 || status > 255)
{
throw vtkm::cont::ErrorBadValue("Rays GetStatusCound: invalid status");
return 0;
}
statusUInt8 = static_cast<vtkm::UInt8>(status);
vtkm::cont::ArrayHandle<vtkm::UInt8> masks;
vtkm::worklet::DispatcherMapField<Mask<vtkm::UInt8>, Device>(Mask<vtkm::UInt8>(statusUInt8))
.Invoke(rays.Status, masks);
vtkm::cont::ArrayHandleCast<vtkm::Id, vtkm::cont::ArrayHandle<vtkm::UInt8>> castedMasks(masks);
const vtkm::Id initVal = 0;
vtkm::Id count = vtkm::cont::DeviceAdapterAlgorithm<Device>::Reduce(castedMasks, initVal);
return count;
}
template <typename Device, typename T>
static vtkm::Id RaysProcessed(Ray<T>& rays, Device)
{
vtkm::Vec<UInt8, 3> maskValues;
maskValues[0] = RAY_TERMINATED;
maskValues[1] = RAY_EXITED_DOMAIN;
maskValues[2] = RAY_ABANDONED;
vtkm::cont::ArrayHandle<vtkm::UInt8> masks;
vtkm::worklet::DispatcherMapField<ManyMask<vtkm::UInt8, 3>, Device>(
ManyMask<vtkm::UInt8, 3>(maskValues))
.Invoke(rays.Status, masks);
vtkm::cont::ArrayHandleCast<vtkm::Id, vtkm::cont::ArrayHandle<vtkm::UInt8>> castedMasks(masks);
const vtkm::Id initVal = 0;
vtkm::Id count = vtkm::cont::DeviceAdapterAlgorithm<Device>::Reduce(castedMasks, initVal);
return count;
}
template <typename Device, typename T>
static vtkm::cont::ArrayHandle<vtkm::UInt8> CompactActiveRays(Ray<T>& rays, Device)
{
vtkm::Vec<UInt8, 1> maskValues;
maskValues[0] = RAY_ACTIVE;
vtkm::UInt8 statusUInt8 = static_cast<vtkm::UInt8>(RAY_ACTIVE);
vtkm::cont::ArrayHandle<vtkm::UInt8> masks;
vtkm::worklet::DispatcherMapField<Mask<vtkm::UInt8>, Device>(Mask<vtkm::UInt8>(statusUInt8))
.Invoke(rays.Status, masks);
//
// Make empty composite vectors so we dont use up extra storage
//
vtkm::IdComponent inComp[3];
inComp[0] = 0;
inComp[1] = 1;
inComp[2] = 2;
vtkm::cont::ArrayHandle<T> emptyHandle;
rays.Normal = vtkm::cont::make_ArrayHandleCompositeVector(
emptyHandle, inComp[0], emptyHandle, inComp[1], emptyHandle, inComp[2]);
rays.Origin = vtkm::cont::make_ArrayHandleCompositeVector(
emptyHandle, inComp[0], emptyHandle, inComp[1], emptyHandle, inComp[2]);
rays.Dir = vtkm::cont::make_ArrayHandleCompositeVector(
emptyHandle, inComp[0], emptyHandle, inComp[1], emptyHandle, inComp[2]);
const vtkm::Int32 numFloatArrays = 18;
vtkm::cont::ArrayHandle<T>* 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<T> compacted;
vtkm::cont::DeviceAdapterAlgorithm<Device>::CopyIf(*floatArrayPointers[i], masks, compacted);
*floatArrayPointers[i] = compacted;
}
//
// restore the composite vectors
//
rays.Normal = vtkm::cont::make_ArrayHandleCompositeVector(
rays.NormalX, inComp[0], rays.NormalY, inComp[1], rays.NormalZ, inComp[2]);
rays.Origin = vtkm::cont::make_ArrayHandleCompositeVector(
rays.OriginX, inComp[0], rays.OriginY, inComp[1], rays.OriginZ, inComp[2]);
rays.Dir = vtkm::cont::make_ArrayHandleCompositeVector(
rays.DirX, inComp[0], rays.DirY, inComp[1], rays.DirZ, inComp[2]);
vtkm::cont::ArrayHandle<vtkm::Id> compactedHits;
vtkm::cont::DeviceAdapterAlgorithm<Device>::CopyIf(rays.HitIdx, masks, compactedHits);
rays.HitIdx = compactedHits;
vtkm::cont::ArrayHandle<vtkm::Id> compactedPixels;
vtkm::cont::DeviceAdapterAlgorithm<Device>::CopyIf(rays.PixelIdx, masks, compactedPixels);
rays.PixelIdx = compactedPixels;
vtkm::cont::ArrayHandle<vtkm::UInt8> compactedStatus;
vtkm::cont::DeviceAdapterAlgorithm<Device>::CopyIf(rays.Status, masks, compactedStatus);
rays.Status = compactedStatus;
rays.NumRays = rays.Status.GetPortalConstControl().GetNumberOfValues();
const size_t bufferCount = static_cast<size_t>(rays.Buffers.size());
for (size_t i = 0; i < bufferCount; ++i)
{
ChannelBufferOperations::Compact(rays.Buffers[i], masks, rays.NumRays, Device());
}
return masks;
}
template <typename Device, typename T>
static void Resize(Ray<T>& rays, const vtkm::Int32 newSize, Device)
{
if (newSize == rays.NumRays)
return; //nothing to do
rays.NumRays = newSize;
if (rays.IntersectionDataEnabled)
{
rays.IntersectionX.PrepareForOutput(rays.NumRays, Device());
rays.IntersectionY.PrepareForOutput(rays.NumRays, Device());
rays.IntersectionZ.PrepareForOutput(rays.NumRays, Device());
rays.U.PrepareForOutput(rays.NumRays, Device());
rays.V.PrepareForOutput(rays.NumRays, Device());
rays.Scalar.PrepareForOutput(rays.NumRays, Device());
rays.NormalX.PrepareForOutput(rays.NumRays, Device());
rays.NormalY.PrepareForOutput(rays.NumRays, Device());
rays.NormalZ.PrepareForOutput(rays.NumRays, Device());
}
rays.OriginX.PrepareForOutput(rays.NumRays, Device());
rays.OriginY.PrepareForOutput(rays.NumRays, Device());
rays.OriginZ.PrepareForOutput(rays.NumRays, Device());
rays.DirX.PrepareForOutput(rays.NumRays, Device());
rays.DirY.PrepareForOutput(rays.NumRays, Device());
rays.DirZ.PrepareForOutput(rays.NumRays, Device());
rays.Distance.PrepareForOutput(rays.NumRays, Device());
rays.MinDistance.PrepareForOutput(rays.NumRays, Device());
rays.MaxDistance.PrepareForOutput(rays.NumRays, Device());
rays.Status.PrepareForOutput(rays.NumRays, Device());
rays.HitIdx.PrepareForOutput(rays.NumRays, Device());
rays.PixelIdx.PrepareForOutput(rays.NumRays, Device());
const size_t bufferCount = static_cast<size_t>(rays.Buffers.size());
for (size_t i = 0; i < bufferCount; ++i)
{
rays.Buffers[i].Resize(rays.NumRays, Device());
}
}
template <typename Device, typename T>
static void CopyDistancesToMin(Ray<T> rays, Device, const T offset = 0.f)
{
vtkm::worklet::DispatcherMapField<CopyAndOffsetMask<T>, Device>(
CopyAndOffsetMask<T>(offset, RAY_EXITED_MESH))
.Invoke(rays.Distance, rays.MinDistance, rays.Status);
}
};
}
}
} // namespace vktm::rendering::raytracing
#endif

@ -0,0 +1,531 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <vtkm/rendering/raytracing/RayTracer.h>
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
namespace detail
{
class IntersectionPoint : public vtkm::worklet::WorkletMapField
{
public:
VTKM_CONT
IntersectionPoint() {}
typedef void ControlSignature(FieldIn<>,
FieldIn<>,
FieldIn<>,
FieldIn<>,
FieldOut<>,
FieldOut<>,
FieldOut<>);
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6, _7);
template <typename Precision>
VTKM_EXEC inline void operator()(const vtkm::Id& hitIndex,
const Precision& distance,
const vtkm::Vec<Precision, 3>& rayDir,
const vtkm::Vec<Precision, 3>& rayOrigin,
Precision& intersectionX,
Precision& intersectionY,
Precision& intersectionZ) const
{
if (hitIndex < 0)
return;
intersectionX = rayOrigin[0] + rayDir[0] * distance;
intersectionY = rayOrigin[1] + rayDir[1] * distance;
intersectionZ = rayOrigin[2] + rayDir[2] * distance;
}
}; //class IntersectionPoint
template <typename Device>
class IntersectionData
{
public:
// Worklet to calutate the normals of a triagle if
// none are stored in the data set
class CalculateNormals : public vtkm::worklet::WorkletMapField
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Int32, 4>> Vec4IntArrayHandle;
typedef typename Vec4IntArrayHandle::ExecutionTypes<Device>::PortalConst IndicesArrayPortal;
IndicesArrayPortal IndicesPortal;
public:
VTKM_CONT
CalculateNormals(const Vec4IntArrayHandle& indices)
: IndicesPortal(indices.PrepareForInput(Device()))
{
}
typedef void ControlSignature(FieldIn<>,
FieldIn<>,
FieldOut<>,
FieldOut<>,
FieldOut<>,
WholeArrayIn<Vec3RenderingTypes>);
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6);
template <typename Precision, typename PointPortalType>
VTKM_EXEC inline void operator()(const vtkm::Id& hitIndex,
const vtkm::Vec<Precision, 3>& rayDir,
Precision& normalX,
Precision& normalY,
Precision& normalZ,
const PointPortalType& points) const
{
if (hitIndex < 0)
return;
vtkm::Vec<Int32, 4> indices = IndicesPortal.Get(hitIndex);
vtkm::Vec<Precision, 3> a = points.Get(indices[1]);
vtkm::Vec<Precision, 3> b = points.Get(indices[2]);
vtkm::Vec<Precision, 3> c = points.Get(indices[3]);
vtkm::Vec<Precision, 3> normal = vtkm::TriangleNormal(a, b, c);
vtkm::Normalize(normal);
//flip the normal if its pointing the wrong way
if (vtkm::dot(normal, rayDir) > 0.f)
normal = -normal;
normalX = normal[0];
normalY = normal[1];
normalZ = normal[2];
}
}; //class CalculateNormals
template <typename Precision>
class LerpScalar : public vtkm::worklet::WorkletMapField
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Int32, 4>> Vec4IntArrayHandle;
typedef typename Vec4IntArrayHandle::ExecutionTypes<Device>::PortalConst IndicesArrayPortal;
IndicesArrayPortal IndicesPortal;
Precision MinScalar;
Precision invDeltaScalar;
public:
VTKM_CONT
LerpScalar(const Vec4IntArrayHandle& indices,
const vtkm::Float32& minScalar,
const vtkm::Float32& maxScalar)
: IndicesPortal(indices.PrepareForInput(Device()))
, MinScalar(minScalar)
{
//Make sure the we don't divide by zero on
//something like an iso-surface
if (maxScalar - MinScalar != 0.f)
invDeltaScalar = 1.f / (maxScalar - MinScalar);
else
invDeltaScalar = 1.f / minScalar;
}
typedef void ControlSignature(FieldIn<>,
FieldIn<>,
FieldIn<>,
FieldOut<>,
WholeArrayIn<ScalarRenderingTypes>);
typedef void ExecutionSignature(_1, _2, _3, _4, _5);
template <typename ScalarPortalType>
VTKM_EXEC void operator()(const vtkm::Id& hitIndex,
const Precision& u,
const Precision& v,
Precision& lerpedScalar,
const ScalarPortalType& scalars) const
{
if (hitIndex < 0)
return;
vtkm::Vec<Int32, 4> indices = IndicesPortal.Get(hitIndex);
Precision n = 1.f - u - v;
Precision aScalar = Precision(scalars.Get(indices[1]));
Precision bScalar = Precision(scalars.Get(indices[2]));
Precision cScalar = Precision(scalars.Get(indices[3]));
lerpedScalar = aScalar * n + bScalar * u + cScalar * v;
//normalize
lerpedScalar = (lerpedScalar - MinScalar) * invDeltaScalar;
}
}; //class LerpScalar
template <typename Precision>
class NodalScalar : public vtkm::worklet::WorkletMapField
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Int32, 4>> Vec4IntArrayHandle;
typedef typename Vec4IntArrayHandle::ExecutionTypes<Device>::PortalConst IndicesArrayPortal;
IndicesArrayPortal IndicesPortal;
Precision MinScalar;
Precision invDeltaScalar;
public:
VTKM_CONT
NodalScalar(const Vec4IntArrayHandle& indices,
const vtkm::Float32& minScalar,
const vtkm::Float32& maxScalar)
: IndicesPortal(indices.PrepareForInput(Device()))
, MinScalar(minScalar)
{
//Make sure the we don't divide by zero on
//something like an iso-surface
if (maxScalar - MinScalar != 0.f)
invDeltaScalar = 1.f / (maxScalar - MinScalar);
else
invDeltaScalar = 1.f / minScalar;
}
typedef void ControlSignature(FieldIn<>, FieldOut<>, WholeArrayIn<ScalarRenderingTypes>);
typedef void ExecutionSignature(_1, _2, _3);
template <typename ScalarPortalType>
VTKM_EXEC void operator()(const vtkm::Id& hitIndex,
Precision& scalar,
const ScalarPortalType& scalars) const
{
if (hitIndex < 0)
return;
vtkm::Vec<Int32, 4> indices = IndicesPortal.Get(hitIndex);
//Todo: one normalization
scalar = Precision(scalars.Get(indices[0]));
//normalize
scalar = (scalar - MinScalar) * invDeltaScalar;
}
}; //class LerpScalar
template <typename Precision>
VTKM_CONT void run(Ray<Precision>& rays,
LinearBVH& bvh,
vtkm::cont::DynamicArrayHandleCoordinateSystem& coordsHandle,
const vtkm::cont::Field* scalarField,
const vtkm::Range& scalarRange)
{
bool isSupportedField = (scalarField->GetAssociation() == vtkm::cont::Field::ASSOC_POINTS ||
scalarField->GetAssociation() == vtkm::cont::Field::ASSOC_CELL_SET);
if (!isSupportedField)
throw vtkm::cont::ErrorBadValue("Field not accociated with cell set or points");
bool isAssocPoints = scalarField->GetAssociation() == vtkm::cont::Field::ASSOC_POINTS;
vtkm::worklet::DispatcherMapField<CalculateNormals, Device>(CalculateNormals(bvh.LeafNodes))
.Invoke(rays.HitIdx, rays.Dir, rays.NormalX, rays.NormalY, rays.NormalZ, coordsHandle);
if (isAssocPoints)
{
vtkm::worklet::DispatcherMapField<LerpScalar<Precision>, Device>(
LerpScalar<Precision>(
bvh.LeafNodes, vtkm::Float32(scalarRange.Min), vtkm::Float32(scalarRange.Max)))
.Invoke(rays.HitIdx, rays.U, rays.V, rays.Scalar, *scalarField);
}
else
{
vtkm::worklet::DispatcherMapField<NodalScalar<Precision>, Device>(
NodalScalar<Precision>(
bvh.LeafNodes, vtkm::Float32(scalarRange.Min), vtkm::Float32(scalarRange.Max)))
.Invoke(rays.HitIdx, rays.Scalar, *scalarField);
}
} // Run
}; // Class IntersectionData
template <typename Device>
class SurfaceColor
{
public:
class MapScalarToColor : public vtkm::worklet::WorkletMapField
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>> ColorArrayHandle;
typedef typename ColorArrayHandle::ExecutionTypes<Device>::PortalConst ColorArrayPortal;
ColorArrayPortal ColorMap;
vtkm::Int32 ColorMapSize;
vtkm::Vec<vtkm::Float32, 3> LightPosition;
vtkm::Vec<vtkm::Float32, 3> LightAbmient;
vtkm::Vec<vtkm::Float32, 3> LightDiffuse;
vtkm::Vec<vtkm::Float32, 3> LightSpecular;
vtkm::Float32 SpecularExponent;
vtkm::Vec<vtkm::Float32, 3> CameraPosition;
vtkm::Vec<vtkm::Float32, 3> LookAt;
vtkm::Vec<vtkm::Float32, 4> BackgroundColor;
public:
VTKM_CONT
MapScalarToColor(const ColorArrayHandle& colorMap,
const vtkm::Int32& colorMapSize,
const vtkm::Vec<vtkm::Float32, 3>& lightPosition,
const vtkm::Vec<vtkm::Float32, 3>& cameraPosition,
const vtkm::Vec<vtkm::Float32, 3>& lookAt,
const vtkm::Vec<vtkm::Float32, 4>& backgroundColor)
: ColorMap(colorMap.PrepareForInput(Device()))
, ColorMapSize(colorMapSize)
, LightPosition(lightPosition)
, CameraPosition(cameraPosition)
, LookAt(lookAt)
, BackgroundColor(backgroundColor)
{
//Set up some default lighting parameters for now
LightAbmient[0] = .5f;
LightAbmient[1] = .5f;
LightAbmient[2] = .5f;
LightDiffuse[0] = .7f;
LightDiffuse[1] = .7f;
LightDiffuse[2] = .7f;
LightSpecular[0] = .7f;
LightSpecular[1] = .7f;
LightSpecular[2] = .7f;
SpecularExponent = 20.f;
}
typedef void ControlSignature(FieldIn<>, FieldIn<>, FieldIn<>, FieldIn<>, WholeArrayInOut<>);
typedef void ExecutionSignature(_1, _2, _3, _4, _5, WorkIndex);
template <typename ColorPortalType, typename Precision>
VTKM_EXEC void operator()(const vtkm::Id& hitIdx,
const Precision& scalar,
const vtkm::Vec<Precision, 3>& normal,
const vtkm::Vec<Precision, 3>& intersection,
ColorPortalType& colors,
const vtkm::Id& idx) const
{
vtkm::Vec<Precision, 4> color;
vtkm::Id offset = idx * 4;
if (hitIdx < 0)
{
color = BackgroundColor;
colors.Set(offset + 0, color[0]);
colors.Set(offset + 1, color[1]);
colors.Set(offset + 2, color[2]);
colors.Set(offset + 3, color[3]);
return;
}
color[0] = colors.Get(offset + 0);
color[1] = colors.Get(offset + 1);
color[2] = colors.Get(offset + 2);
color[3] = colors.Get(offset + 3);
vtkm::Vec<Precision, 3> lightDir = LightPosition - intersection;
vtkm::Vec<Precision, 3> viewDir = CameraPosition - LookAt;
vtkm::Normalize(lightDir);
vtkm::Normalize(viewDir);
//Diffuse lighting
Precision cosTheta = vtkm::dot(normal, lightDir);
//clamp tp [0,1]
const Precision zero = 0.f;
const Precision one = 1.f;
cosTheta = vtkm::Min(vtkm::Max(cosTheta, zero), one);
//Specular lighting
vtkm::Vec<Precision, 3> reflect = 2.f * vtkm::dot(lightDir, normal) * normal - lightDir;
vtkm::Normalize(reflect);
Precision cosPhi = vtkm::dot(reflect, viewDir);
Precision specularConstant = Precision(pow(vtkm::Max(cosPhi, zero), SpecularExponent));
vtkm::Int32 colorIdx = vtkm::Int32(scalar * Precision(ColorMapSize - 1));
//Just in case clamp the value to the valid range
colorIdx = (colorIdx < 0) ? 0 : colorIdx;
colorIdx = (colorIdx > ColorMapSize - 1) ? ColorMapSize - 1 : colorIdx;
color = ColorMap.Get(colorIdx);
color[0] *= vtkm::Min(
LightAbmient[0] + LightDiffuse[0] * cosTheta + LightSpecular[0] * specularConstant, one);
color[1] *= vtkm::Min(
LightAbmient[1] + LightDiffuse[1] * cosTheta + LightSpecular[1] * specularConstant, one);
color[2] *= vtkm::Min(
LightAbmient[2] + LightDiffuse[2] * cosTheta + LightSpecular[2] * specularConstant, one);
//color[0] *= vtkm::Min(LightDiffuse[0] * cosTheta, one);
//color[1] *= vtkm::Min(LightDiffuse[1] * cosTheta, one);
//color[2] *= vtkm::Min(LightDiffuse[2] * cosTheta, one);
colors.Set(offset + 0, color[0]);
colors.Set(offset + 1, color[1]);
colors.Set(offset + 2, color[2]);
colors.Set(offset + 3, color[3]);
}
}; //class MapScalarToColor
template <typename Precision>
VTKM_CONT void run(Ray<Precision>& rays,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& colorMap,
const vtkm::rendering::raytracing::Camera& camera,
const vtkm::Vec<vtkm::Float32, 4> backgroundColor)
{
// TODO: support light positions
vtkm::Vec<vtkm::Float32, 3> scale(5, 5, 5);
vtkm::Vec<vtkm::Float32, 3> lightPosition = camera.GetPosition() + scale * camera.GetUp();
const vtkm::Int32 colorMapSize = vtkm::Int32(colorMap.GetNumberOfValues());
vtkm::worklet::DispatcherMapField<MapScalarToColor, Device>(
MapScalarToColor(colorMap,
colorMapSize,
lightPosition,
camera.GetPosition(),
camera.GetLookAt(),
backgroundColor))
.Invoke(rays.HitIdx, rays.Scalar, rays.Normal, rays.Intersection, rays.Buffers.at(0).Buffer);
}
}; // class SurfaceColor
} // namespace detail
RayTracer::RayTracer()
{
}
void RayTracer::SetBackgroundColor(const vtkm::Vec<vtkm::Float32, 4>& backgroundColor)
{
BackgroundColor = backgroundColor;
}
Camera& RayTracer::GetCamera()
{
return camera;
}
void RayTracer::SetData(const vtkm::cont::DynamicArrayHandleCoordinateSystem& coordsHandle,
const vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>>& indices,
const vtkm::cont::Field& scalarField,
const vtkm::Id& numberOfTriangles,
const vtkm::Range& scalarRange,
const vtkm::Bounds& dataBounds)
{
CoordsHandle = coordsHandle;
Indices = indices;
ScalarField = &scalarField;
NumberOfTriangles = numberOfTriangles;
ScalarRange = scalarRange;
DataBounds = dataBounds;
Bvh.SetData(coordsHandle, indices);
}
void RayTracer::SetColorMap(const vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& colorMap)
{
ColorMap = colorMap;
}
template <typename Precision>
struct RayTracer::RenderFunctor
{
protected:
vtkm::rendering::raytracing::RayTracer* Self;
vtkm::rendering::raytracing::Ray<Precision>& Rays;
public:
VTKM_CONT
RenderFunctor(vtkm::rendering::raytracing::RayTracer* self,
vtkm::rendering::raytracing::Ray<Precision>& rays)
: Self(self)
, Rays(rays)
{
}
template <typename Device>
VTKM_CONT bool operator()(Device)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
this->Self->RenderOnDevice(this->Rays, Device());
return true;
}
};
void RayTracer::Render(Ray<vtkm::Float32>& rays)
{
RenderFunctor<vtkm::Float32> functor(this, rays);
vtkm::cont::TryExecute(functor);
}
void
RayTracer::Render(Ray<vtkm::Float64> &rays)
{
RenderFunctor<vtkm::Float64> functor(this, rays);
vtkm::cont::TryExecute(functor);
}
template <typename Device, typename Precision>
void RayTracer::RenderOnDevice(Ray<Precision>& rays, Device)
{
rays.EnableIntersectionData(Device());
Logger* logger = Logger::GetInstance();
vtkm::cont::Timer<Device> renderTimer;
vtkm::Float64 time = 0.;
logger->OpenLogEntry("ray_tracer");
logger->AddLogData("device", GetDeviceString(Device()));
Bvh.ConstructOnDevice(Device());
logger->AddLogData("triangles", NumberOfTriangles);
logger->AddLogData("num_rays", rays.NumRays);
if (NumberOfTriangles > 0)
{
vtkm::cont::Timer<Device> timer;
// Find distance to intersection
TriangleIntersector<Device, TriLeafIntersector<Moller>> intersector;
intersector.run(rays, Bvh, CoordsHandle);
time = timer.GetElapsedTime();
logger->AddLogData("intersect", time);
timer.Reset();
// Calculate normal and scalar value (TODO: find a better name)
detail::IntersectionData<Device> intData;
intData.run(rays, Bvh, CoordsHandle, ScalarField, ScalarRange);
time = timer.GetElapsedTime();
logger->AddLogData("intersection_data", time);
timer.Reset();
// Find the intersection point from hit distance
vtkm::worklet::DispatcherMapField<detail::IntersectionPoint, Device>(
detail::IntersectionPoint())
.Invoke(rays.HitIdx,
rays.Distance,
rays.Dir,
rays.Origin,
rays.IntersectionX,
rays.IntersectionY,
rays.IntersectionZ);
time = timer.GetElapsedTime();
logger->AddLogData("find_point", time);
timer.Reset();
// Calculate the color at the intersection point
detail::SurfaceColor<Device> surfaceColor;
surfaceColor.run(rays, ColorMap, camera, BackgroundColor);
time = timer.GetElapsedTime();
logger->AddLogData("shade", time);
timer.Reset();
}
time = renderTimer.GetElapsedTime();
logger->CloseLogEntry(time);
} // RenderOnDevice
}
}
} // namespace vtkm::rendering::raytracing

@ -19,12 +19,16 @@
//============================================================================
#ifndef vtk_m_rendering_raytracing_RayTracer_h
#define vtk_m_rendering_raytracing_RayTracer_h
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/raytracing/Camera.h>
#include <vtkm/rendering/raytracing/Logger.h>
#include <vtkm/rendering/raytracing/RayTracingTypeDefs.h>
#include <vtkm/rendering/raytracing/TriangleIntersector.h>
#include <vtkm/worklet/DispatcherMapField.h>
@ -37,345 +41,12 @@ namespace rendering
namespace raytracing
{
class IntersectionPoint : public vtkm::worklet::WorkletMapField
{
public:
VTKM_CONT
IntersectionPoint() {}
typedef void ControlSignature(FieldIn<>,
FieldIn<>,
FieldIn<>,
FieldIn<>,
FieldOut<>,
FieldOut<>,
FieldOut<>);
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6, _7);
VTKM_EXEC
void operator()(const vtkm::Id& hitIndex,
const vtkm::Float32& distance,
const vtkm::Vec<vtkm::Float32, 3>& rayDir,
const vtkm::Vec<vtkm::Float32, 3>& rayOrigin,
vtkm::Float32& intersectionX,
vtkm::Float32& intersectionY,
vtkm::Float32& intersectionZ) const
{
if (hitIndex < 0)
return;
intersectionX = rayOrigin[0] + rayDir[0] * distance;
intersectionY = rayOrigin[1] + rayDir[1] * distance;
intersectionZ = rayOrigin[2] + rayDir[2] * distance;
}
}; //class IntersectionPoint
template <typename DeviceAdapter>
class Reflector
{
public:
// Worklet to calutate the normals of a triagle if
// none are stored in the data set
class CalculateNormals : public vtkm::worklet::WorkletMapField
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Int32, 4>> Vec4IntArrayHandle;
typedef
typename Vec4IntArrayHandle::ExecutionTypes<DeviceAdapter>::PortalConst IndicesArrayPortal;
IndicesArrayPortal IndicesPortal;
public:
VTKM_CONT
CalculateNormals(const Vec4IntArrayHandle& indices)
: IndicesPortal(indices.PrepareForInput(DeviceAdapter()))
{
}
typedef void ControlSignature(FieldIn<>,
FieldIn<>,
FieldOut<>,
FieldOut<>,
FieldOut<>,
WholeArrayIn<Vec3RenderingTypes>);
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6);
template <typename PointPortalType>
VTKM_EXEC void operator()(const vtkm::Id& hitIndex,
const vtkm::Vec<vtkm::Float32, 3>& rayDir,
vtkm::Float32& normalX,
vtkm::Float32& normalY,
vtkm::Float32& normalZ,
const PointPortalType& points) const
{
if (hitIndex < 0)
return;
vtkm::Vec<Int32, 4> indices = IndicesPortal.Get(hitIndex);
vtkm::Vec<Float32, 3> a = points.Get(indices[1]);
vtkm::Vec<Float32, 3> b = points.Get(indices[2]);
vtkm::Vec<Float32, 3> c = points.Get(indices[3]);
vtkm::Vec<Float32, 3> normal = vtkm::TriangleNormal(a, b, c);
vtkm::Normalize(normal);
//flip the normal if its pointing the wrong way
if (vtkm::dot(normal, rayDir) < 0.f)
normal = -normal;
normalX = normal[0];
normalY = normal[1];
normalZ = normal[2];
}
}; //class CalculateNormals
class LerpScalar : public vtkm::worklet::WorkletMapField
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Int32, 4>> Vec4IntArrayHandle;
typedef
typename Vec4IntArrayHandle::ExecutionTypes<DeviceAdapter>::PortalConst IndicesArrayPortal;
IndicesArrayPortal IndicesPortal;
vtkm::Float32 MinScalar;
vtkm::Float32 invDeltaScalar;
public:
VTKM_CONT
LerpScalar(const Vec4IntArrayHandle& indices,
const vtkm::Float32& minScalar,
const vtkm::Float32& maxScalar)
: IndicesPortal(indices.PrepareForInput(DeviceAdapter()))
, MinScalar(minScalar)
{
//Make sure the we don't divide by zero on
//something like an iso-surface
if (maxScalar - MinScalar != 0.f)
invDeltaScalar = 1.f / (maxScalar - MinScalar);
else
invDeltaScalar = 1.f / minScalar;
}
typedef void ControlSignature(FieldIn<>,
FieldIn<>,
FieldIn<>,
FieldOut<>,
WholeArrayIn<ScalarRenderingTypes>);
typedef void ExecutionSignature(_1, _2, _3, _4, _5);
template <typename ScalarPortalType>
VTKM_EXEC void operator()(const vtkm::Id& hitIndex,
const vtkm::Float32& u,
const vtkm::Float32& v,
vtkm::Float32& lerpedScalar,
const ScalarPortalType& scalars) const
{
if (hitIndex < 0)
return;
vtkm::Vec<Int32, 4> indices = IndicesPortal.Get(hitIndex);
vtkm::Float32 n = 1.f - u - v;
vtkm::Float32 aScalar = vtkm::Float32(scalars.Get(indices[1]));
vtkm::Float32 bScalar = vtkm::Float32(scalars.Get(indices[2]));
vtkm::Float32 cScalar = vtkm::Float32(scalars.Get(indices[3]));
lerpedScalar = aScalar * n + bScalar * u + cScalar * v;
//normalize
lerpedScalar = (lerpedScalar - MinScalar) * invDeltaScalar;
}
}; //class LerpScalar
class NodalScalar : public vtkm::worklet::WorkletMapField
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Int32, 4>> Vec4IntArrayHandle;
typedef
typename Vec4IntArrayHandle::ExecutionTypes<DeviceAdapter>::PortalConst IndicesArrayPortal;
IndicesArrayPortal IndicesPortal;
vtkm::Float32 MinScalar;
vtkm::Float32 invDeltaScalar;
public:
VTKM_CONT
NodalScalar(const Vec4IntArrayHandle& indices,
const vtkm::Float32& minScalar,
const vtkm::Float32& maxScalar)
: IndicesPortal(indices.PrepareForInput(DeviceAdapter()))
, MinScalar(minScalar)
{
//Make sure the we don't divide by zero on
//something like an iso-surface
if (maxScalar - MinScalar != 0.f)
invDeltaScalar = 1.f / (maxScalar - MinScalar);
else
invDeltaScalar = 1.f / minScalar;
}
typedef void ControlSignature(FieldIn<>, FieldOut<>, WholeArrayIn<ScalarRenderingTypes>);
typedef void ExecutionSignature(_1, _2, _3);
template <typename ScalarPortalType>
VTKM_EXEC void operator()(const vtkm::Id& hitIndex,
vtkm::Float32& scalar,
const ScalarPortalType& scalars) const
{
if (hitIndex < 0)
return;
vtkm::Vec<Int32, 4> indices = IndicesPortal.Get(hitIndex);
//Todo: one normalization
scalar = vtkm::Float32(scalars.Get(indices[0]));
//normalize
scalar = (scalar - MinScalar) * invDeltaScalar;
}
}; //class LerpScalar
VTKM_CONT
void run(Ray<DeviceAdapter>& rays,
LinearBVH& bvh,
vtkm::cont::DynamicArrayHandleCoordinateSystem& coordsHandle,
const vtkm::cont::Field* scalarField,
const vtkm::Range& scalarRange)
{
bool isSupportedField = (scalarField->GetAssociation() == vtkm::cont::Field::ASSOC_POINTS ||
scalarField->GetAssociation() == vtkm::cont::Field::ASSOC_CELL_SET);
if (!isSupportedField)
throw vtkm::cont::ErrorBadValue("Field not accociated with cell set or points");
bool isAssocPoints = scalarField->GetAssociation() == vtkm::cont::Field::ASSOC_POINTS;
vtkm::worklet::DispatcherMapField<CalculateNormals>(CalculateNormals(bvh.LeafNodes))
.Invoke(rays.HitIdx, rays.Dir, rays.NormalX, rays.NormalY, rays.NormalZ, coordsHandle);
if (isAssocPoints)
{
vtkm::worklet::DispatcherMapField<LerpScalar>(
LerpScalar(bvh.LeafNodes, vtkm::Float32(scalarRange.Min), vtkm::Float32(scalarRange.Max)))
.Invoke(rays.HitIdx, rays.U, rays.V, rays.Scalar, *scalarField);
}
else
{
vtkm::worklet::DispatcherMapField<NodalScalar>(
NodalScalar(bvh.LeafNodes, vtkm::Float32(scalarRange.Min), vtkm::Float32(scalarRange.Max)))
.Invoke(rays.HitIdx, rays.Scalar, *scalarField);
}
} // Run
}; // Class reflector
template <typename DeviceAdapter>
class SurfaceColor
{
public:
class MapScalarToColor : public vtkm::worklet::WorkletMapField
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>> ColorArrayHandle;
typedef typename ColorArrayHandle::ExecutionTypes<DeviceAdapter>::PortalConst ColorArrayPortal;
ColorArrayPortal ColorMap;
vtkm::Int32 ColorMapSize;
vtkm::Vec<vtkm::Float32, 3> LightPosition;
vtkm::Vec<vtkm::Float32, 3> LightAbmient;
vtkm::Vec<vtkm::Float32, 3> LightDiffuse;
vtkm::Vec<vtkm::Float32, 3> LightSpecular;
vtkm::Float32 SpecularExponent;
vtkm::Vec<vtkm::Float32, 3> CameraPosition;
vtkm::Vec<vtkm::Float32, 4> BackgroundColor;
public:
VTKM_CONT
MapScalarToColor(const ColorArrayHandle& colorMap,
const vtkm::Int32& colorMapSize,
const vtkm::Vec<vtkm::Float32, 3>& lightPosition,
const vtkm::Vec<vtkm::Float32, 3>& cameraPosition,
const vtkm::Vec<vtkm::Float32, 4>& backgroundColor)
: ColorMap(colorMap.PrepareForInput(DeviceAdapter()))
, ColorMapSize(colorMapSize)
, LightPosition(lightPosition)
, CameraPosition(cameraPosition)
, BackgroundColor(backgroundColor)
{
//Set up some default lighting parameters for now
LightAbmient[0] = .3f;
LightAbmient[1] = .3f;
LightAbmient[2] = .3f;
LightDiffuse[0] = .7f;
LightDiffuse[1] = .7f;
LightDiffuse[2] = .7f;
LightSpecular[0] = .7f;
LightSpecular[1] = .7f;
LightSpecular[2] = .7f;
SpecularExponent = 80.f;
}
typedef void ControlSignature(FieldIn<>, FieldIn<>, FieldIn<>, FieldIn<>, FieldOut<>);
typedef void ExecutionSignature(_1, _2, _3, _4, _5);
VTKM_EXEC
void operator()(const vtkm::Id& hitIdx,
const vtkm::Float32& scalar,
const vtkm::Vec<vtkm::Float32, 3>& normal,
const vtkm::Vec<vtkm::Float32, 3>& intersection,
vtkm::Vec<vtkm::Float32, 4>& color) const
{
if (hitIdx < 0)
{
color = BackgroundColor;
return;
}
vtkm::Vec<vtkm::Float32, 3> lightDir = LightPosition - intersection;
vtkm::Vec<vtkm::Float32, 3> viewDir = CameraPosition - intersection;
vtkm::Normalize(lightDir);
vtkm::Normalize(viewDir);
//Diffuse lighting
vtkm::Float32 cosTheta = vtkm::dot(-normal, lightDir);
//clamp tp [0,1]
cosTheta = vtkm::Min(vtkm::Max(cosTheta, 0.f), 1.f);
//Specular lighting
vtkm::Vec<vtkm::Float32, 3> halfVector = viewDir + lightDir;
vtkm::Normalize(halfVector);
vtkm::Float32 cosPhi = vtkm::dot(-normal, halfVector);
vtkm::Float32 specularConstant = vtkm::Float32(pow(fmaxf(cosPhi, 0.f), SpecularExponent));
vtkm::Int32 colorIdx = vtkm::Int32(scalar * vtkm::Float32(ColorMapSize - 1));
//Just in case clamp the value to the valid range
colorIdx = (colorIdx < 0) ? 0 : colorIdx;
colorIdx = (colorIdx > ColorMapSize - 1) ? ColorMapSize - 1 : colorIdx;
color = ColorMap.Get(colorIdx);
//std::cout<<" Before "<<color<< " at index "<<colorIdx<<" ";
//std::cout<<"CosTheta "<<cosTheta<<" CosPhi "<<cosPhi<<" | ";
color[0] *= vtkm::Min(
LightAbmient[0] + LightDiffuse[0] * cosTheta + LightSpecular[0] * specularConstant, 1.f);
color[1] *= vtkm::Min(
LightAbmient[1] + LightDiffuse[1] * cosTheta + LightSpecular[1] * specularConstant, 1.f);
color[2] *= vtkm::Min(
LightAbmient[2] + LightDiffuse[2] * cosTheta + LightSpecular[2] * specularConstant, 1.f);
//color[0] =1.f;
//std::cout<<color;
}
}; //class MapScalarToColor
VTKM_CONT
void run(Ray<DeviceAdapter>& rays,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& colorMap,
ColorBuffer4f& colorBuffer,
const vtkm::Vec<vtkm::Float32, 3> cameraPosition,
const vtkm::Vec<vtkm::Float32, 4> backgroundColor)
{
vtkm::Vec<vtkm::Float32, 3> lightPosition = cameraPosition;
// lightPosition[0] = 0.f;
// lightPosition[1] = 0.f;
// lightPosition[2] = -10.f;
const vtkm::Int32 colorMapSize = vtkm::Int32(colorMap.GetNumberOfValues());
vtkm::worklet::DispatcherMapField<MapScalarToColor>(
MapScalarToColor(colorMap, colorMapSize, lightPosition, cameraPosition, backgroundColor))
.Invoke(rays.HitIdx, rays.Scalar, rays.Normal, rays.Intersection, colorBuffer);
}
}; // class SurfaceColor
template <typename DeviceAdapter>
class RayTracer
{
protected:
bool IsSceneDirty;
Ray<DeviceAdapter> Rays;
LinearBVHBuilder<DeviceAdapter> Builder;
LinearBVH Bvh;
Camera<DeviceAdapter> camera;
Camera camera;
vtkm::cont::DynamicArrayHandleCoordinateSystem CoordsHandle;
const vtkm::cont::Field* ScalarField;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> Indices;
@ -385,19 +56,21 @@ protected:
vtkm::Range ScalarRange;
vtkm::Bounds DataBounds;
vtkm::Vec<vtkm::Float32, 4> BackgroundColor;
template <typename Precision>
struct RenderFunctor;
template <typename Device, typename Precision>
void RenderOnDevice(Ray<Precision>& rays, Device);
public:
VTKM_CONT
RayTracer() { IsSceneDirty = true; }
RayTracer();
VTKM_CONT
void SetBackgroundColor(const vtkm::Vec<vtkm::Float32, 4>& backgroundColor)
{
BackgroundColor = backgroundColor;
}
void SetBackgroundColor(const vtkm::Vec<vtkm::Float32, 4>& backgroundColor);
VTKM_CONT
Camera<DeviceAdapter>& GetCamera() { return camera; }
Camera& GetCamera();
VTKM_CONT
void SetData(const vtkm::cont::DynamicArrayHandleCoordinateSystem& coordsHandle,
@ -405,57 +78,14 @@ public:
const vtkm::cont::Field& scalarField,
const vtkm::Id& numberOfTriangles,
const vtkm::Range& scalarRange,
const vtkm::Bounds& dataBounds)
{
IsSceneDirty = true;
CoordsHandle = coordsHandle;
Indices = indices;
ScalarField = &scalarField;
NumberOfTriangles = numberOfTriangles;
ScalarRange = scalarRange;
DataBounds = dataBounds;
}
const vtkm::Bounds& dataBounds);
VTKM_CONT
void SetColorMap(const vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& colorMap)
{
ColorMap = colorMap;
}
void SetColorMap(const vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& colorMap);
VTKM_CONT
void Init()
{
Builder.run(CoordsHandle, Indices, NumberOfTriangles, Bvh);
camera.CreateRays(Rays, DataBounds);
IsSceneDirty = false;
}
void Render(vtkm::rendering::raytracing::Ray<vtkm::Float32>& rays);
void Render(vtkm::rendering::raytracing::Ray<vtkm::Float64>& rays);
VTKM_CONT
void Render(CanvasRayTracer* canvas)
{
if (IsSceneDirty)
{
Init();
}
TriangleIntersector<DeviceAdapter> intersector;
intersector.run(Rays, Bvh, CoordsHandle);
Reflector<DeviceAdapter> reflector;
reflector.run(Rays, Bvh, CoordsHandle, ScalarField, ScalarRange);
vtkm::worklet::DispatcherMapField<IntersectionPoint>(IntersectionPoint())
.Invoke(Rays.HitIdx,
Rays.Distance,
Rays.Dir,
Rays.Origin,
Rays.IntersectionX,
Rays.IntersectionY,
Rays.IntersectionZ);
SurfaceColor<DeviceAdapter> surfaceColor;
surfaceColor.run(Rays, ColorMap, camera.FrameBuffer, camera.GetPosition(), BackgroundColor);
camera.WriteToSurface(canvas, Rays.Distance);
}
}; //class RayTracer
}
}

@ -19,14 +19,84 @@
//============================================================================
#ifndef vtk_m_rendering_raytracing_RayTracingTypeDefs_h
#define vtk_m_rendering_raytracing_RayTracingTypeDefs_h
#include <type_traits>
#include <vtkm/ListTag.h>
#include <vtkm/Math.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayHandleCompositeVector.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/DeviceAdapterListTag.h>
#include <vtkm/cont/DynamicArrayHandle.h>
namespace vtkm
{
namespace rendering
{
// A more useful bounds check that tells you where it happened
#ifndef NDEBUG
#define BOUNDS_CHECK(HANDLE, INDEX) \
{ \
BoundsCheck((HANDLE), (INDEX), __FILE__, __LINE__); \
}
#else
#define BOUNDS_CHECK(HANDLE, INDEX)
#endif
template <typename ArrayHandleType>
inline void BoundsCheck(const ArrayHandleType& handle,
const vtkm::Id& index,
const char* file,
int line)
{
if (index < 0 || index >= handle.GetNumberOfValues())
printf("Bad Index %d at file %s line %d\n", (int)index, file, line);
}
namespace raytracing
{
template <typename T>
VTKM_EXEC_CONT inline void GetInfinity(T& vtkmNotUsed(infinity));
//{
// static_assert(!std::is_floating_point<T>(),
// "Get Infinity can only be called with float or double");
//}
template <>
VTKM_EXEC_CONT inline void GetInfinity<vtkm::Float32>(vtkm::Float32& infinity)
{
infinity = vtkm::Infinity32();
}
template <>
VTKM_EXEC_CONT inline void GetInfinity<vtkm::Float64>(vtkm::Float64& infinity)
{
infinity = vtkm::Infinity64();
}
template <typename Device>
inline std::string GetDeviceString(Device);
template <>
inline std::string GetDeviceString<vtkm::cont::DeviceAdapterTagSerial>(
vtkm::cont::DeviceAdapterTagSerial)
{
return "serial";
}
template <>
inline std::string GetDeviceString<vtkm::cont::DeviceAdapterTagTBB>(vtkm::cont::DeviceAdapterTagTBB)
{
return "tbb";
}
template <>
inline std::string GetDeviceString<vtkm::cont::DeviceAdapterTagCuda>(
vtkm::cont::DeviceAdapterTagCuda)
{
return "cuda";
}
typedef vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>> ColorBuffer4f;
typedef vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>> ColorBuffer4b;
@ -47,6 +117,73 @@ typedef vtkm::Float64 ScalarD;
struct ScalarRenderingTypes : vtkm::ListTagBase<ScalarF, ScalarD>
{
};
//Restrict Coordinate types to explicit for volume renderer
namespace detail
{
typedef vtkm::cont::ArrayHandleCompositeVectorType<vtkm::cont::ArrayHandle<vtkm::Float32>,
vtkm::cont::ArrayHandle<vtkm::Float32>,
vtkm::cont::ArrayHandle<vtkm::Float32>>::type
ArrayHandleCompositeVectorFloat32_3Default;
typedef vtkm::cont::ArrayHandleCompositeVectorType<vtkm::cont::ArrayHandle<vtkm::Float64>,
vtkm::cont::ArrayHandle<vtkm::Float64>,
vtkm::cont::ArrayHandle<vtkm::Float64>>::type
ArrayHandleCompositeVectorFloat64_3Default;
struct StructuredStorageListTagCoordinateSystem
: vtkm::ListTagBase<vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag,
vtkm::cont::ArrayHandleCartesianProduct<
vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
vtkm::cont::ArrayHandle<vtkm::FloatDefault>>::StorageTag>
{
};
/*
* This would be for support of curvilinear meshes
struct StructuredStorageListTagCoordinateSystem
: vtkm::ListTagJoin<
VTKM_DEFAULT_STORAGE_LIST_TAG,
vtkm::ListTagBase<vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag,
vtkm::cont::ArrayHandleCartesianProduct<
vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
vtkm::cont::ArrayHandle<vtkm::FloatDefault> >::StorageTag > >
{ };*/
} // namespace detail
/*
* This is a less restrictive type list for Explicit meshes
struct ExplicitCoordinatesType : vtkm::ListTagBase<vtkm::Vec<vtkm::Float32,3>,
vtkm::Vec<vtkm::Float64,3> > {};
struct StorageListTagExplicitCoordinateSystem
: vtkm::ListTagBase<vtkm::cont::StorageTagBasic,
detail::ArrayHandleCompositeVectorFloat32_3Default::StorageTag,
detail::ArrayHandleCompositeVectorFloat64_3Default::StorageTag >{ };
*/
//Super restrictive
struct ExplicitCoordinatesType
: vtkm::ListTagBase<vtkm::Vec<vtkm::Float32, 3>, vtkm::Vec<vtkm::Float64, 3>>
{
};
struct StorageListTagExplicitCoordinateSystem : vtkm::ListTagBase<vtkm::cont::StorageTagBasic>
{
};
typedef detail::StructuredStorageListTagCoordinateSystem StructuredStorage;
typedef vtkm::cont::DynamicArrayHandleBase<ExplicitCoordinatesType, StructuredStorage>
DynamicArrayHandleStructuredCoordinateSystem;
typedef vtkm::cont::DynamicArrayHandleBase<ExplicitCoordinatesType,
StorageListTagExplicitCoordinateSystem>
DynamicArrayHandleExplicitCoordinateSystem;
}
}
} //namespace vtkm::rendering::raytracing

File diff suppressed because it is too large Load Diff

@ -26,12 +26,16 @@
#include <math.h>
#include <stdio.h>
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/CoordinateSystem.h>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/raytracing/Camera.h>
#include <vtkm/rendering/raytracing/Logger.h>
#include <vtkm/rendering/raytracing/Ray.h>
#include <vtkm/rendering/raytracing/RayTracingTypeDefs.h>
#include <vtkm/worklet/DispatcherMapField.h>
@ -299,8 +303,9 @@ public:
}; // class UniformLocator
} //namespace
template <typename Device>
class VolumeRendererStructured
{
public:
@ -308,13 +313,12 @@ public:
typedef vtkm::cont::ArrayHandleCartesianProduct<DefaultHandle, DefaultHandle, DefaultHandle>
CartesianArrayHandle;
template <typename LocatorType>
template <typename Device, typename LocatorType>
class Sampler : public vtkm::worklet::WorkletMapField
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>> ColorArrayHandle;
typedef typename ColorArrayHandle::ExecutionTypes<Device>::PortalConst ColorArrayPortal;
vtkm::Vec<vtkm::Float32, 3> CameraPosition;
ColorArrayPortal ColorMap;
vtkm::Id ColorMapSize;
vtkm::Float32 MinScalar;
@ -324,14 +328,12 @@ public:
public:
VTKM_CONT
Sampler(vtkm::Vec<vtkm::Float32, 3> cameraPosition,
const ColorArrayHandle& colorMap,
Sampler(const ColorArrayHandle& colorMap,
const vtkm::Float32& minScalar,
const vtkm::Float32& maxScalar,
const vtkm::Float32& sampleDistance,
const LocatorType& locator)
: CameraPosition(cameraPosition)
, ColorMap(colorMap.PrepareForInput(Device()))
: ColorMap(colorMap.PrepareForInput(Device()))
, MinScalar(minScalar)
, SampleDistance(sampleDistance)
, Locator(locator)
@ -344,25 +346,34 @@ public:
}
typedef void ControlSignature(FieldIn<>,
FieldIn<>,
FieldOut<>,
FieldIn<>,
WholeArrayInOut<>,
WholeArrayIn<ScalarRenderingTypes>);
typedef void ExecutionSignature(_1, _2, _3, _4);
typedef void ExecutionSignature(_1, _2, _3, _4, _5, WorkIndex);
template <typename ScalarPortalType>
template <typename ScalarPortalType, typename ColorBufferType>
VTKM_EXEC void operator()(const vtkm::Vec<vtkm::Float32, 3>& rayDir,
const vtkm::Vec<vtkm::Float32, 3>& rayOrigin,
const vtkm::Float32& minDistance,
vtkm::Vec<vtkm::Float32, 4>& color,
ScalarPortalType& scalars) const
ColorBufferType& colorBuffer,
ScalarPortalType& scalars,
const vtkm::Id& pixelIndex) const
{
color[0] = 0.f;
color[1] = 0.f;
color[2] = 0.f;
color[3] = 0.f;
vtkm::Vec<vtkm::Float32, 4> color;
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 0);
color[0] = colorBuffer.Get(pixelIndex * 4 + 0);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 1);
color[1] = colorBuffer.Get(pixelIndex * 4 + 1);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 2);
color[2] = colorBuffer.Get(pixelIndex * 4 + 2);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 3);
color[3] = colorBuffer.Get(pixelIndex * 4 + 3);
if (minDistance == -1.f)
return; //TODO: Compact? or just image subset...
//get the initial sample position;
vtkm::Vec<vtkm::Float32, 3> sampleLocation;
sampleLocation = CameraPosition + (0.0001f + minDistance) * rayDir;
sampleLocation = rayOrigin + (0.0001f + minDistance) * rayDir;
/*
7----------6
/| /|
@ -388,7 +399,8 @@ public:
vtkm::Float32 scalar7 = 0.f;
vtkm::Vec<vtkm::Id, 3> cell(0, 0, 0);
vtkm::Vec<vtkm::Float32, 3> invSpacing;
vtkm::Vec<vtkm::Float32, 3> invSpacing(0.f, 0.f, 0.f);
while (Locator.IsInside(sampleLocation))
{
@ -465,20 +477,29 @@ public:
if (color[3] >= 1.f)
break;
}
color[0] = vtkm::Min(color[0], 1.f);
color[1] = vtkm::Min(color[1], 1.f);
color[2] = vtkm::Min(color[2], 1.f);
color[3] = vtkm::Min(color[3], 1.f);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 0);
colorBuffer.Set(pixelIndex * 4 + 0, color[0]);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 1);
colorBuffer.Set(pixelIndex * 4 + 1, color[1]);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 2);
colorBuffer.Set(pixelIndex * 4 + 2, color[2]);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 3);
colorBuffer.Set(pixelIndex * 4 + 3, color[3]);
}
}; //Sampler
template <typename LocatorType>
template <typename Device, typename LocatorType>
class SamplerCellAssoc : public vtkm::worklet::WorkletMapField
{
private:
typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>> ColorArrayHandle;
typedef typename ColorArrayHandle::ExecutionTypes<Device>::PortalConst ColorArrayPortal;
vtkm::Vec<vtkm::Float32, 3> CameraPosition;
ColorArrayPortal ColorMap;
vtkm::Id ColorMapSize;
vtkm::Float32 MinScalar;
@ -488,14 +509,12 @@ public:
public:
VTKM_CONT
SamplerCellAssoc(vtkm::Vec<vtkm::Float32, 3> cameraPosition,
const ColorArrayHandle& colorMap,
SamplerCellAssoc(const ColorArrayHandle& colorMap,
const vtkm::Float32& minScalar,
const vtkm::Float32& maxScalar,
const vtkm::Float32& sampleDistance,
const LocatorType& locator)
: CameraPosition(cameraPosition)
, ColorMap(colorMap.PrepareForInput(Device()))
: ColorMap(colorMap.PrepareForInput(Device()))
, MinScalar(minScalar)
, SampleDistance(sampleDistance)
, Locator(locator)
@ -508,25 +527,34 @@ public:
}
typedef void ControlSignature(FieldIn<>,
FieldIn<>,
FieldOut<>,
FieldIn<>,
WholeArrayInOut<>,
WholeArrayIn<ScalarRenderingTypes>);
typedef void ExecutionSignature(_1, _2, _3, _4);
typedef void ExecutionSignature(_1, _2, _3, _4, _5, WorkIndex);
template <typename ScalarPortalType>
template <typename ScalarPortalType, typename ColorBufferType>
VTKM_EXEC void operator()(const vtkm::Vec<vtkm::Float32, 3>& rayDir,
const vtkm::Vec<vtkm::Float32, 3>& rayOrigin,
const vtkm::Float32& minDistance,
vtkm::Vec<vtkm::Float32, 4>& color,
const ScalarPortalType& scalars) const
ColorBufferType& colorBuffer,
const ScalarPortalType& scalars,
const vtkm::Id& pixelIndex) const
{
color[0] = 0.f;
color[1] = 0.f;
color[2] = 0.f;
color[3] = 0.f;
vtkm::Vec<vtkm::Float32, 4> color;
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 0);
color[0] = colorBuffer.Get(pixelIndex * 4 + 0);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 1);
color[1] = colorBuffer.Get(pixelIndex * 4 + 1);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 2);
color[2] = colorBuffer.Get(pixelIndex * 4 + 2);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 3);
color[3] = colorBuffer.Get(pixelIndex * 4 + 3);
if (minDistance == -1.f)
return; //TODO: Compact? or just image subset...
//get the initial sample position;
vtkm::Vec<vtkm::Float32, 3> sampleLocation;
sampleLocation = CameraPosition + (0.0001f + minDistance) * rayDir;
sampleLocation = rayOrigin + (0.0001f + minDistance) * rayDir;
/*
7----------6
@ -542,9 +570,9 @@ public:
vtkm::Float32 ty = 2.f;
vtkm::Float32 tz = 2.f;
vtkm::Float32 scalar0 = 0.f;
vtkm::Vec<vtkm::Float32, 4> sampleColor(0, 0, 0, 0);
vtkm::Vec<vtkm::Float32, 3> bottomLeft(0, 0, 0);
vtkm::Vec<vtkm::Float32, 3> invSpacing;
vtkm::Vec<vtkm::Float32, 4> sampleColor(0.f, 0.f, 0.f, 0.f);
vtkm::Vec<vtkm::Float32, 3> bottomLeft(0.f, 0.f, 0.f);
vtkm::Vec<vtkm::Float32, 3> invSpacing(0.f, 0.f, 0.f);
vtkm::Vec<vtkm::Id, 3> cell(0, 0, 0);
while (Locator.IsInside(sampleLocation))
{
@ -588,11 +616,19 @@ public:
ty = (sampleLocation[1] - bottomLeft[1]) * invSpacing[1];
tz = (sampleLocation[2] - bottomLeft[2]) * invSpacing[2];
}
color[0] = vtkm::Min(color[0], 1.f);
color[1] = vtkm::Min(color[1], 1.f);
color[2] = vtkm::Min(color[2], 1.f);
color[3] = vtkm::Min(color[3], 1.f);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 0);
colorBuffer.Set(pixelIndex * 4 + 0, color[0]);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 1);
colorBuffer.Set(pixelIndex * 4 + 1, color[1]);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 2);
colorBuffer.Set(pixelIndex * 4 + 2, color[2]);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 3);
colorBuffer.Set(pixelIndex * 4 + 3, color[3]);
}
}; //SamplerCell
@ -604,12 +640,10 @@ public:
vtkm::Float32 Xmax;
vtkm::Float32 Ymax;
vtkm::Float32 Zmax;
vtkm::Vec<vtkm::Float32, 3> CameraPosition;
public:
VTKM_CONT
CalcRayStart(vtkm::Vec<vtkm::Float32, 3> cameraPosition, const vtkm::Bounds boundingBox)
: CameraPosition(cameraPosition)
CalcRayStart(const vtkm::Bounds boundingBox)
{
Xmin = static_cast<vtkm::Float32>(boundingBox.X.Min);
Xmax = static_cast<vtkm::Float32>(boundingBox.X.Max);
@ -625,24 +659,28 @@ public:
VTKM_EXEC
vtkm::Float32 rcp_safe(vtkm::Float32 f) const { return rcp((fabs(f) < 1e-8f) ? 1e-8f : f); }
typedef void ControlSignature(FieldIn<>, FieldOut<>, FieldOut<>);
typedef void ExecutionSignature(_1, _2, _3);
VTKM_EXEC
void operator()(const vtkm::Vec<vtkm::Float32, 3>& rayDir,
vtkm::Float32& minDistance,
vtkm::Float32& maxDistance) const
typedef void ControlSignature(FieldIn<>, FieldOut<>, FieldOut<>, FieldIn<>);
typedef void ExecutionSignature(_1, _2, _3, _4);
template <typename Precision>
VTKM_EXEC void operator()(const vtkm::Vec<Precision, 3>& rayDir,
vtkm::Float32& minDistance,
vtkm::Float32& maxDistance,
const vtkm::Vec<Precision, 3>& rayOrigin) const
{
vtkm::Float32 dirx = rayDir[0];
vtkm::Float32 diry = rayDir[1];
vtkm::Float32 dirz = rayDir[2];
vtkm::Float32 dirx = static_cast<vtkm::Float32>(rayDir[0]);
vtkm::Float32 diry = static_cast<vtkm::Float32>(rayDir[1]);
vtkm::Float32 dirz = static_cast<vtkm::Float32>(rayDir[2]);
vtkm::Float32 origx = static_cast<vtkm::Float32>(rayOrigin[0]);
vtkm::Float32 origy = static_cast<vtkm::Float32>(rayOrigin[1]);
vtkm::Float32 origz = static_cast<vtkm::Float32>(rayOrigin[2]);
vtkm::Float32 invDirx = rcp_safe(dirx);
vtkm::Float32 invDiry = rcp_safe(diry);
vtkm::Float32 invDirz = rcp_safe(dirz);
vtkm::Float32 odirx = CameraPosition[0] * invDirx;
vtkm::Float32 odiry = CameraPosition[1] * invDiry;
vtkm::Float32 odirz = CameraPosition[2] * invDirz;
vtkm::Float32 odirx = origx * invDirx;
vtkm::Float32 odiry = origy * invDiry;
vtkm::Float32 odirz = origz * invDirz;
vtkm::Float32 xmin = Xmin * invDirx - odirx;
vtkm::Float32 ymin = Ymin * invDiry - odiry;
@ -651,6 +689,7 @@ public:
vtkm::Float32 ymax = Ymax * invDiry - odiry;
vtkm::Float32 zmax = Zmax * invDirz - odirz;
minDistance = vtkm::Max(
vtkm::Max(vtkm::Max(vtkm::Min(ymin, ymax), vtkm::Min(xmin, xmax)), vtkm::Min(zmin, zmax)),
0.f);
@ -674,19 +713,40 @@ public:
{
}
typedef void ControlSignature(FieldInOut<>);
typedef void ExecutionSignature(_1);
VTKM_EXEC
void operator()(vtkm::Vec<vtkm::Float32, 4>& color) const
typedef void ControlSignature(FieldIn<>, WholeArrayInOut<>);
typedef void ExecutionSignature(_1, _2);
template <typename ColorBufferType>
VTKM_EXEC void operator()(const vtkm::Id& pixelIndex, ColorBufferType& colorBuffer) const
{
vtkm::Vec<vtkm::Float32, 4> color;
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 0);
color[0] = colorBuffer.Get(pixelIndex * 4 + 0);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 1);
color[1] = colorBuffer.Get(pixelIndex * 4 + 1);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 2);
color[2] = colorBuffer.Get(pixelIndex * 4 + 2);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 3);
color[3] = colorBuffer.Get(pixelIndex * 4 + 3);
if (color[3] >= 1.f)
return;
vtkm::Float32 alpha = BackgroundColor[3] * (1.f - color[3]);
color[0] = color[0] + BackgroundColor[0] * alpha;
color[1] = color[1] + BackgroundColor[1] * alpha;
color[2] = color[2] + BackgroundColor[2] * alpha;
color[3] = alpha + color[3];
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 0);
colorBuffer.Set(pixelIndex * 4 + 0, color[0]);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 1);
colorBuffer.Set(pixelIndex * 4 + 1, color[1]);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 2);
colorBuffer.Set(pixelIndex * 4 + 2, color[2]);
BOUNDS_CHECK(colorBuffer, pixelIndex * 4 + 3);
colorBuffer.Set(pixelIndex * 4 + 3, color[3]);
}
}; //class CompositeBackground
@ -694,13 +754,17 @@ public:
VolumeRendererStructured()
{
IsSceneDirty = false;
DoCompositeBackground = true;
IsUniformDataSet = true;
SampleDistance = -1.f;
DoCompositeBackground = false;
}
VTKM_CONT
Camera<Device>& GetCamera() { return camera; }
void SetCompositeBackground(bool compositeBackground)
{
DoCompositeBackground = compositeBackground;
}
VTKM_CONT
void SetColorMap(const vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& colorMap)
@ -708,50 +772,82 @@ public:
ColorMap = colorMap;
}
VTKM_CONT
void Init()
{
camera.CreateRays(Rays, DataBounds);
IsSceneDirty = true;
}
VTKM_CONT
void SetData(const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField,
const vtkm::Bounds& coordsBounds,
const vtkm::cont::CellSetStructured<3>& cellset,
const vtkm::Range& scalarRange)
{
if (coords.GetData().IsSameType(CartesianArrayHandle()))
IsUniformDataSet = false;
IsSceneDirty = true;
SpatialExtent = coords.GetBounds();
Coordinates = coords.GetData();
ScalarField = &scalarField;
DataBounds = coordsBounds;
Cellset = cellset;
ScalarRange = scalarRange;
}
VTKM_CONT
void Render(CanvasRayTracer* canvas)
template <typename Precision>
struct RenderFunctor
{
if (IsSceneDirty)
protected:
vtkm::rendering::raytracing::VolumeRendererStructured* Self;
vtkm::rendering::raytracing::Ray<Precision>& Rays;
public:
VTKM_CONT
RenderFunctor(vtkm::rendering::raytracing::VolumeRendererStructured* self,
vtkm::rendering::raytracing::Ray<Precision>& rays)
: Self(self)
, Rays(rays)
{
Init();
}
template <typename Device>
VTKM_CONT bool operator()(Device)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
this->Self->RenderOnDevice(this->Rays, Device());
return true;
}
};
template <typename Precision>
VTKM_CONT void Render(vtkm::rendering::raytracing::Ray<Precision>& rays)
{
RenderFunctor<Precision> functor(this, rays);
vtkm::cont::TryExecute(functor);
}
template <typename Precision, typename Device>
VTKM_CONT void RenderOnDevice(vtkm::rendering::raytracing::Ray<Precision>& rays, Device)
{
vtkm::cont::Timer<Device> renderTimer;
Logger* logger = Logger::GetInstance();
logger->OpenLogEntry("volume_render_structured");
logger->AddLogData("device", GetDeviceString(Device()));
if (SampleDistance <= 0.f)
{
vtkm::Vec<vtkm::Float32, 3> extent;
extent[0] = static_cast<vtkm::Float32>(this->DataBounds.X.Length());
extent[1] = static_cast<vtkm::Float32>(this->DataBounds.Y.Length());
extent[2] = static_cast<vtkm::Float32>(this->DataBounds.Z.Length());
extent[0] = static_cast<vtkm::Float32>(this->SpatialExtent.X.Length());
extent[1] = static_cast<vtkm::Float32>(this->SpatialExtent.Y.Length());
extent[2] = static_cast<vtkm::Float32>(this->SpatialExtent.Z.Length());
const vtkm::Float32 defaultNumberOfSamples = 200.f;
SampleDistance = vtkm::Magnitude(extent) / defaultNumberOfSamples;
}
vtkm::worklet::DispatcherMapField<CalcRayStart, Device>(
CalcRayStart(camera.GetPosition(), this->DataBounds))
.Invoke(Rays.Dir, Rays.MinDistance, Rays.MaxDistance);
vtkm::cont::Timer<Device> timer;
vtkm::worklet::DispatcherMapField<CalcRayStart, Device>(CalcRayStart(this->SpatialExtent))
.Invoke(rays.Dir, rays.MinDistance, rays.MaxDistance, rays.Origin);
vtkm::Float64 time = timer.GetElapsedTime();
logger->AddLogData("calc_ray_start", time);
timer.Reset();
bool isSupportedField = (ScalarField->GetAssociation() == vtkm::cont::Field::ASSOC_POINTS ||
ScalarField->GetAssociation() == vtkm::cont::Field::ASSOC_CELL_SET);
if (!isSupportedField)
@ -760,32 +856,29 @@ public:
if (IsUniformDataSet)
{
vtkm::cont::ArrayHandleUniformPointCoordinates vertices;
vertices = Coordinates.Cast<vtkm::cont::ArrayHandleUniformPointCoordinates>();
UniformLocator<Device> locator(vertices, Cellset);
if (isAssocPoints)
{
vtkm::worklet::DispatcherMapField<Sampler<UniformLocator<Device>>, Device>(
Sampler<UniformLocator<Device>>(camera.GetPosition(),
ColorMap,
vtkm::Float32(ScalarRange.Min),
vtkm::Float32(ScalarRange.Max),
SampleDistance,
locator))
.Invoke(Rays.Dir, Rays.MinDistance, camera.FrameBuffer, *ScalarField);
vtkm::worklet::DispatcherMapField<Sampler<Device, UniformLocator<Device>>, Device>(
Sampler<Device, UniformLocator<Device>>(ColorMap,
vtkm::Float32(ScalarRange.Min),
vtkm::Float32(ScalarRange.Max),
SampleDistance,
locator))
.Invoke(rays.Dir, rays.Origin, rays.MinDistance, rays.Buffers.at(0).Buffer, *ScalarField);
}
else
{
vtkm::worklet::DispatcherMapField<SamplerCellAssoc<UniformLocator<Device>>>(
SamplerCellAssoc<UniformLocator<Device>>(camera.GetPosition(),
ColorMap,
vtkm::Float32(ScalarRange.Min),
vtkm::Float32(ScalarRange.Max),
SampleDistance,
locator))
.Invoke(Rays.Dir, Rays.MinDistance, camera.FrameBuffer, *ScalarField);
vtkm::worklet::DispatcherMapField<SamplerCellAssoc<Device, UniformLocator<Device>>>(
SamplerCellAssoc<Device, UniformLocator<Device>>(ColorMap,
vtkm::Float32(ScalarRange.Min),
vtkm::Float32(ScalarRange.Max),
SampleDistance,
locator))
.Invoke(rays.Dir, rays.Origin, rays.MinDistance, rays.Buffers.at(0).Buffer, *ScalarField);
}
}
else
@ -795,34 +888,44 @@ public:
RectilinearLocator<Device> locator(vertices, Cellset);
if (isAssocPoints)
{
vtkm::worklet::DispatcherMapField<Sampler<RectilinearLocator<Device>>, Device>(
Sampler<RectilinearLocator<Device>>(camera.GetPosition(),
ColorMap,
vtkm::Float32(ScalarRange.Min),
vtkm::Float32(ScalarRange.Max),
SampleDistance,
locator))
.Invoke(Rays.Dir, Rays.MinDistance, camera.FrameBuffer, *ScalarField);
vtkm::worklet::DispatcherMapField<Sampler<Device, RectilinearLocator<Device>>, Device>(
Sampler<Device, RectilinearLocator<Device>>(ColorMap,
vtkm::Float32(ScalarRange.Min),
vtkm::Float32(ScalarRange.Max),
SampleDistance,
locator))
.Invoke(rays.Dir, rays.Origin, rays.MinDistance, rays.Buffers.at(0).Buffer, *ScalarField);
}
else
{
vtkm::worklet::DispatcherMapField<SamplerCellAssoc<RectilinearLocator<Device>>, Device>(
SamplerCellAssoc<RectilinearLocator<Device>>(camera.GetPosition(),
ColorMap,
vtkm::Float32(ScalarRange.Min),
vtkm::Float32(ScalarRange.Max),
SampleDistance,
locator))
.Invoke(Rays.Dir, Rays.MinDistance, camera.FrameBuffer, *ScalarField);
vtkm::worklet::DispatcherMapField<SamplerCellAssoc<Device, RectilinearLocator<Device>>,
Device>(
SamplerCellAssoc<Device, RectilinearLocator<Device>>(ColorMap,
vtkm::Float32(ScalarRange.Min),
vtkm::Float32(ScalarRange.Max),
SampleDistance,
locator))
.Invoke(rays.Dir, rays.Origin, rays.MinDistance, rays.Buffers.at(0).Buffer, *ScalarField);
}
}
time = timer.GetElapsedTime();
logger->AddLogData("sample", time);
timer.Reset();
if (DoCompositeBackground)
{
vtkm::cont::ArrayHandleCounting<vtkm::Id> rayIterator(0, 1, rays.NumRays);
vtkm::worklet::DispatcherMapField<CompositeBackground>(CompositeBackground(BackgroundColor))
.Invoke(camera.FrameBuffer);
.Invoke(rayIterator, rays.Buffers.at(0).Buffer);
time = timer.GetElapsedTime();
logger->AddLogData("compsosite_background", time);
timer.Reset();
}
camera.WriteToSurface(canvas, Rays.MinDistance);
time = renderTimer.GetElapsedTime();
logger->CloseLogEntry(time);
} //Render
VTKM_CONT
@ -839,17 +942,11 @@ public:
BackgroundColor = backgroundColor;
}
void SetCompositeBackground(bool compositeBackground)
{
DoCompositeBackground = compositeBackground;
}
protected:
bool IsSceneDirty;
bool IsUniformDataSet;
bool DoCompositeBackground;
VolumeRay<Device> Rays;
Camera<Device> camera;
bool IsUniformDataSet;
vtkm::Bounds SpatialExtent;
vtkm::cont::DynamicArrayHandleCoordinateSystem Coordinates;
vtkm::cont::CellSetStructured<3> Cellset;
const vtkm::cont::Field* ScalarField;
@ -857,7 +954,6 @@ protected:
vtkm::Float32 SampleDistance;
vtkm::Vec<vtkm::Float32, 4> BackgroundColor;
vtkm::Range ScalarRange;
vtkm::Bounds DataBounds;
};
}
}

@ -46,6 +46,106 @@ public:
void operator()(T& outValue) const { outValue = Value; }
}; //class MemSet
template <typename FloatType>
class CopyAndOffset : public vtkm::worklet::WorkletMapField
{
FloatType Offset;
public:
VTKM_CONT
CopyAndOffset(const FloatType offset = 0.00001)
: Offset(offset)
{
}
typedef void ControlSignature(FieldIn<>, FieldOut<>);
typedef void ExecutionSignature(_1, _2);
VTKM_EXEC inline void operator()(const FloatType& inValue, FloatType& outValue) const
{
outValue = inValue + Offset;
}
}; //class Copy and iffset
template <typename FloatType>
class CopyAndOffsetMask : public vtkm::worklet::WorkletMapField
{
FloatType Offset;
vtkm::UInt8 MaskValue;
public:
VTKM_CONT
CopyAndOffsetMask(const FloatType offset = 0.00001, const vtkm::UInt8 mask = 1)
: Offset(offset)
, MaskValue(mask)
{
}
typedef void ControlSignature(FieldIn<>, FieldInOut<>, FieldIn<>);
typedef void ExecutionSignature(_1, _2, _3);
template <typename MaskType>
VTKM_EXEC inline void operator()(const FloatType& inValue,
FloatType& outValue,
const MaskType& mask) const
{
if (mask == MaskValue)
outValue = inValue + Offset;
}
}; //class Copy and iffset
template <class T>
class Mask : public vtkm::worklet::WorkletMapField
{
T Value;
public:
VTKM_CONT
Mask(T value)
: Value(value)
{
}
typedef void ControlSignature(FieldIn<>, FieldOut<>);
typedef void ExecutionSignature(_1, _2);
template <typename O>
VTKM_EXEC void operator()(const T& inValue, O& outValue) const
{
if (inValue == Value)
outValue = static_cast<O>(1);
else
outValue = static_cast<O>(0);
}
}; //class mask
template <class T, int N>
class ManyMask : public vtkm::worklet::WorkletMapField
{
vtkm::Vec<T, N> Values;
public:
VTKM_CONT
ManyMask(vtkm::Vec<T, N> values)
: Values(values)
{
}
typedef void ControlSignature(FieldIn<>, FieldOut<>);
typedef void ExecutionSignature(_1, _2);
template <typename O>
VTKM_EXEC void operator()(const T& inValue, O& outValue) const
{
bool doMask = false;
for (vtkm::Int32 i = 0; i < N; ++i)
{
if (inValue == Values[i])
doMask = true;
}
if (doMask)
outValue = static_cast<O>(1);
else
outValue = static_cast<O>(0);
}
}; //class doube mask
struct MaxValue
{
template <typename T>

@ -25,6 +25,7 @@ set(headers
vtkm_declare_headers(${headers})
set(unit_tests
UnitTestMapperConnectivity.cxx
UnitTestMapperRayTracer.cxx
UnitTestMapperVolume.cxx
)

@ -0,0 +1,57 @@
//============================================================================
// 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.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <vtkm/cont/DeviceAdapter.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/rendering/Actor.h>
#include <vtkm/rendering/Canvas.h>
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/rendering/MapperConnectivity.h>
#include <vtkm/rendering/Scene.h>
#include <vtkm/rendering/View3D.h>
#include <vtkm/rendering/testing/RenderTest.h>
namespace
{
void RenderTests()
{
typedef vtkm::rendering::MapperConnectivity M;
typedef vtkm::rendering::CanvasRayTracer C;
typedef vtkm::rendering::View3D V3;
vtkm::cont::testing::MakeTestDataSet maker;
vtkm::rendering::ColorTable colorTable("thermal");
vtkm::rendering::testing::Render<M, C, V3>(
maker.Make3DRegularDataSet0(), "pointvar", colorTable, "reg3D.pnm");
vtkm::rendering::testing::Render<M, C, V3>(
maker.Make3DRectilinearDataSet0(), "pointvar", colorTable, "rect3D.pnm");
vtkm::rendering::testing::Render<M, C, V3>(
maker.Make3DExplicitDataSet5(), "pointvar", colorTable, "explicit3D.pnm");
}
} //namespace
int UnitTestMapperConnectivity(int, char* [])
{
return vtkm::cont::testing::Testing::Run(RenderTests);
}