Merge topic 'line_rendering'

8e0a0308 Handles the case when the passed canvas has rendered data.
b727377f Refactoring
44357d51 Apply external faces filter on cellset before wireframing
7e95269c Refactoring wireframing code
5738e895 Wireframe rendering
657b0b94 Applies `clang-format` and minor refactoring
af2acc57 Implements a simple line renderer using Xialin Wu's algorithm

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Matt Larsen <mlarsen@cs.uoregon.edu>
Merge-request: !895
This commit is contained in:
Matt Larsen 2017-08-24 19:48:43 +00:00 committed by Kitware Robot
commit 93aa64109f
6 changed files with 931 additions and 0 deletions

@ -41,6 +41,7 @@ set(headers
MapperRayTracer.h MapperRayTracer.h
MapperVolume.h MapperVolume.h
MapperConnectivity.h MapperConnectivity.h
MapperWireframer.h
TextAnnotation.h TextAnnotation.h
TextAnnotationBillboard.h TextAnnotationBillboard.h
TextAnnotationScreen.h TextAnnotationScreen.h
@ -73,6 +74,7 @@ set(sources
MapperRayTracer.cxx MapperRayTracer.cxx
MapperVolume.cxx MapperVolume.cxx
MapperConnectivity.cxx MapperConnectivity.cxx
MapperWireframer.cxx
Scene.cxx Scene.cxx
TextAnnotation.cxx TextAnnotation.cxx
TextAnnotationBillboard.cxx TextAnnotationBillboard.cxx
@ -126,6 +128,8 @@ set(osmesa_sources
# This list of sources has code that uses devices and so might need to be # This list of sources has code that uses devices and so might need to be
# compiled with a device-specific compiler (like CUDA). # compiled with a device-specific compiler (like CUDA).
set(device_sources set(device_sources
Mapper.cxx
MapperWireframer.cxx
CanvasRayTracer.cxx CanvasRayTracer.cxx
ConnectivityProxy.cxx ConnectivityProxy.cxx
raytracing/BoundingVolumeHierarchy.cxx raytracing/BoundingVolumeHierarchy.cxx

@ -0,0 +1,269 @@
//============================================================================
// 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 2016 Sandia Corporation.
// Copyright 2016 UT-Battelle, LLC.
// Copyright 2016 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/Assert.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/exec/CellEdge.h>
#include <vtkm/filter/ExternalFaces.h>
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/rendering/MapperRayTracer.h>
#include <vtkm/rendering/MapperWireframer.h>
#include <vtkm/rendering/Wireframer.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/ScatterCounting.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/WorkletMapTopology.h>
namespace vtkm
{
namespace rendering
{
namespace
{
struct EdgesCounter : public vtkm::worklet::WorkletMapPointToCell
{
typedef void ControlSignature(CellSetIn cellSet, FieldOutCell<> numEdges);
typedef _2 ExecutionSignature(CellShape shape, PointCount numPoints);
using InputDomain = _1;
template <typename CellShapeTag>
VTKM_EXEC vtkm::IdComponent operator()(CellShapeTag shape, vtkm::IdComponent numPoints) const
{
if (shape.Id == vtkm::CELL_SHAPE_LINE)
{
return 1;
}
else
{
return vtkm::exec::CellEdgeNumberOfEdges(numPoints, shape, *this);
}
}
}; // struct EdgesCounter
struct EdgesExtracter : public vtkm::worklet::WorkletMapPointToCell
{
typedef void ControlSignature(CellSetIn cellSet, FieldOutCell<> edgeIndices);
typedef void ExecutionSignature(CellShape, PointIndices, VisitIndex, _2);
using InputDomain = _1;
using ScatterType = vtkm::worklet::ScatterCounting;
VTKM_CONT
template <typename CountArrayType, typename DeviceTag>
EdgesExtracter(const CountArrayType& counts, DeviceTag device)
: Scatter(counts, device)
{
}
VTKM_CONT ScatterType GetScatter() const { return this->Scatter; }
template <typename CellShapeTag, typename PointIndexVecType, typename EdgeIndexVecType>
VTKM_EXEC void operator()(CellShapeTag shape,
const PointIndexVecType& pointIndices,
vtkm::IdComponent visitIndex,
EdgeIndexVecType& edgeIndices) const
{
vtkm::Id p1, p2;
if (shape.Id == vtkm::CELL_SHAPE_LINE)
{
p1 = pointIndices[0];
p2 = pointIndices[1];
}
else
{
vtkm::Vec<vtkm::IdComponent, 2> localEdgeIndices = vtkm::exec::CellEdgeLocalIndices(
pointIndices.GetNumberOfComponents(), visitIndex, shape, *this);
p1 = pointIndices[localEdgeIndices[0]];
p2 = pointIndices[localEdgeIndices[1]];
}
// These indices need to be arranged in a definite order, as they will later be sorted to
// detect duplicates
edgeIndices[0] = p1 < p2 ? p1 : p2;
edgeIndices[1] = p1 < p2 ? p2 : p1;
}
private:
ScatterType Scatter;
}; // struct EdgesExtracter
struct ExtractUniqueEdges
{
vtkm::cont::DynamicCellSet CellSet;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 2>> EdgeIndices;
VTKM_CONT
ExtractUniqueEdges(const vtkm::cont::DynamicCellSet& cellSet)
: CellSet(cellSet)
{
}
template <typename DeviceTag>
VTKM_CONT bool operator()(DeviceTag)
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceTag);
vtkm::cont::ArrayHandle<vtkm::IdComponent> counts;
vtkm::worklet::DispatcherMapTopology<EdgesCounter, DeviceTag>().Invoke(CellSet, counts);
EdgesExtracter extractWorklet(counts, DeviceTag());
vtkm::worklet::DispatcherMapTopology<EdgesExtracter, DeviceTag> extractDispatcher(
extractWorklet);
extractDispatcher.Invoke(CellSet, EdgeIndices);
vtkm::cont::DeviceAdapterAlgorithm<DeviceTag>::template Sort<vtkm::Id2>(EdgeIndices);
vtkm::cont::DeviceAdapterAlgorithm<DeviceTag>::template Unique<vtkm::Id2>(EdgeIndices);
return true;
}
}; // struct ExtractUniqueEdges
} // namespace
struct MapperWireframer::InternalsType
{
InternalsType()
: InternalsType(nullptr, false, false)
{
}
InternalsType(vtkm::rendering::Canvas* canvas, bool showInternalZones, bool isOverlay)
: Canvas(canvas)
, ShowInternalZones(showInternalZones)
, IsOverlay(isOverlay)
{
}
vtkm::rendering::Canvas* Canvas;
bool ShowInternalZones;
bool IsOverlay;
}; // struct MapperWireframer::InternalsType
MapperWireframer::MapperWireframer()
: Internals(new InternalsType(nullptr, false, false))
{
}
MapperWireframer::~MapperWireframer()
{
}
vtkm::rendering::Canvas* MapperWireframer::GetCanvas() const
{
return this->Internals->Canvas;
}
void MapperWireframer::SetCanvas(vtkm::rendering::Canvas* canvas)
{
this->Internals->Canvas = canvas;
}
bool MapperWireframer::GetShowInternalZones() const
{
return this->Internals->ShowInternalZones;
}
void MapperWireframer::SetShowInternalZones(bool showInternalZones)
{
this->Internals->ShowInternalZones = showInternalZones;
}
bool MapperWireframer::GetIsOverlay() const
{
return this->Internals->IsOverlay;
}
void MapperWireframer::SetIsOverlay(bool isOverlay)
{
this->Internals->IsOverlay = isOverlay;
}
void MapperWireframer::StartScene()
{
// Nothing needs to be done.
}
void MapperWireframer::EndScene()
{
// Nothing needs to be done.
}
void MapperWireframer::RenderCells(const vtkm::cont::DynamicCellSet& inCellSet,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& inScalarField,
const vtkm::rendering::ColorTable& colorTable,
const vtkm::rendering::Camera& camera,
const vtkm::Range& scalarRange)
{
vtkm::cont::DynamicCellSet cellSet = inCellSet;
vtkm::cont::Field field = inScalarField;
if (!(this->Internals->ShowInternalZones))
{
// If internal zones are to be hidden, the number of edges processed can be reduced by
// running the external faces filter on the input cell set.
vtkm::cont::DataSet dataSet;
dataSet.AddCoordinateSystem(coords);
dataSet.AddCellSet(inCellSet);
vtkm::filter::ExternalFaces externalFaces;
externalFaces.SetCompactPoints(false);
externalFaces.SetPassPolyData(true);
vtkm::filter::Result result = externalFaces.Execute(dataSet);
externalFaces.MapFieldOntoOutput(result, inScalarField);
cellSet = result.GetDataSet().GetCellSet();
field = result.GetDataSet().GetField(0);
}
// Extract unique edges from the cell set.
ExtractUniqueEdges extracter(cellSet);
vtkm::cont::TryExecute(extracter);
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 2>> edgeIndices = extracter.EdgeIndices;
Wireframer renderer(
this->Internals->Canvas, this->Internals->ShowInternalZones, this->Internals->IsOverlay);
// Render the cell set using a raytracer, on a separate canvas, and use the generated depth
// buffer, which represents the solid mesh, to avoid drawing on the internal zones
if (!(this->Internals->ShowInternalZones) && !(this->Internals->IsOverlay))
{
CanvasRayTracer canvas(this->Internals->Canvas->GetWidth(),
this->Internals->Canvas->GetHeight());
canvas.SetBackgroundColor(vtkm::rendering::Color::white);
canvas.Initialize();
canvas.Activate();
canvas.Clear();
MapperRayTracer raytracer;
raytracer.SetCanvas(&canvas);
raytracer.SetActiveColorTable(colorTable);
raytracer.RenderCells(cellSet, coords, field, colorTable, camera, scalarRange);
renderer.SetSolidDepthBuffer(canvas.GetDepthBuffer());
}
else if (this->Internals->IsOverlay)
{
renderer.SetSolidDepthBuffer(this->Internals->Canvas->GetDepthBuffer());
}
renderer.SetCamera(camera);
renderer.SetColorMap(this->ColorMap);
renderer.SetData(coords, edgeIndices, field, scalarRange);
renderer.Render();
}
vtkm::rendering::Mapper* MapperWireframer::NewCopy() const
{
return new vtkm::rendering::MapperWireframer(*this);
}
}
} // namespace vtkm::rendering

@ -0,0 +1,72 @@
//============================================================================
// 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_MapperWireframer_h
#define vtk_m_rendering_MapperWireframer_h
#include <memory>
#include <vtkm/cont/CoordinateSystem.h>
#include <vtkm/cont/DynamicCellSet.h>
#include <vtkm/cont/Field.h>
#include <vtkm/rendering/Camera.h>
#include <vtkm/rendering/Canvas.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/Mapper.h>
namespace vtkm
{
namespace rendering
{
class VTKM_RENDERING_EXPORT MapperWireframer : public Mapper
{
public:
VTKM_CONT
MapperWireframer();
virtual ~MapperWireframer();
virtual vtkm::rendering::Canvas* GetCanvas() const VTKM_OVERRIDE;
virtual void SetCanvas(vtkm::rendering::Canvas* canvas) VTKM_OVERRIDE;
bool GetShowInternalZones() const;
void SetShowInternalZones(bool showInternalZones);
bool GetIsOverlay() const;
void SetIsOverlay(bool isOverlay);
virtual void StartScene() VTKM_OVERRIDE;
virtual void EndScene() 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 vtkm::rendering::Mapper* NewCopy() const VTKM_OVERRIDE;
private:
struct InternalsType;
std::shared_ptr<InternalsType> Internals;
}; // class MapperWireframer
}
} // namespace vtkm::rendering
#endif // vtk_m_rendering_MapperWireframer_h

533
vtkm/rendering/Wireframer.h Normal file

@ -0,0 +1,533 @@
//============================================================================
// 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 2016 Sandia Corporation.
// Copyright 2016 UT-Battelle, LLC.
// Copyright 2016 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_Wireframer_h
#define vtk_m_rendering_Wireframer_h
#include <vtkm/Assert.h>
#include <vtkm/Math.h>
#include <vtkm/Types.h>
#include <vtkm/VectorAnalysis.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DynamicArrayHandle.h>
#include <vtkm/exec/AtomicArray.h>
#include <vtkm/rendering/MatrixHelpers.h>
#include <vtkm/rendering/Triangulator.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/WorkletMapField.h>
namespace vtkm
{
namespace rendering
{
namespace
{
using ColorMapHandle = vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>;
using IndicesHandle = vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 2>>;
using PackedFrameBufferHandle = vtkm::cont::ArrayHandle<vtkm::Int64>;
// Depth value of 1.0f
const vtkm::Int64 ClearDepth = 0x3F800000;
// Packed frame buffer value with color set as white and depth as 1.0f
const vtkm::Int64 ClearValue = 0x3F800000FFFFFFFF;
VTKM_EXEC_CONT
vtkm::Float32 IntegerPart(vtkm::Float32 x)
{
return vtkm::Floor(x);
}
VTKM_EXEC_CONT
vtkm::Float32 FractionalPart(vtkm::Float32 x)
{
return x - vtkm::Floor(x);
}
VTKM_EXEC_CONT
vtkm::Float32 ReverseFractionalPart(vtkm::Float32 x)
{
return 1.0f - FractionalPart(x);
}
VTKM_EXEC_CONT
vtkm::UInt32 ScaleColorComponent(vtkm::Float32 c)
{
vtkm::Int32 t = vtkm::Int32(c * 256.0f);
return vtkm::UInt32(t < 0 ? 0 : (t > 255 ? 255 : t));
}
vtkm::UInt32 PackColor(vtkm::Float32 r, vtkm::Float32 g, vtkm::Float32 b, vtkm::Float32 a);
VTKM_EXEC_CONT
vtkm::UInt32 PackColor(const vtkm::Vec<vtkm::Float32, 4>& color)
{
return PackColor(color[0], color[1], color[2], color[3]);
}
VTKM_EXEC_CONT
vtkm::UInt32 PackColor(vtkm::Float32 r, vtkm::Float32 g, vtkm::Float32 b, vtkm::Float32 a)
{
vtkm::UInt32 packed = (ScaleColorComponent(r) << 24);
packed |= (ScaleColorComponent(g) << 16);
packed |= (ScaleColorComponent(b) << 8);
packed |= ScaleColorComponent(a);
return packed;
}
void UnpackColor(vtkm::UInt32 color,
vtkm::Float32& r,
vtkm::Float32& g,
vtkm::Float32& b,
vtkm::Float32& a);
VTKM_EXEC_CONT
void UnpackColor(vtkm::UInt32 packedColor, vtkm::Vec<vtkm::Float32, 4>& color)
{
UnpackColor(packedColor, color[0], color[1], color[2], color[3]);
}
VTKM_EXEC_CONT
void UnpackColor(vtkm::UInt32 color,
vtkm::Float32& r,
vtkm::Float32& g,
vtkm::Float32& b,
vtkm::Float32& a)
{
r = vtkm::Float32((color & 0xFF000000) >> 24) / 255.0f;
g = vtkm::Float32((color & 0x00FF0000) >> 16) / 255.0f;
b = vtkm::Float32((color & 0x0000FF00) >> 8) / 255.0f;
a = vtkm::Float32((color & 0x000000FF)) / 255.0f;
}
union PackedValue {
struct PackedFloats
{
vtkm::Float32 Color;
vtkm::Float32 Depth;
} Floats;
struct PackedInts
{
vtkm::UInt32 Color;
vtkm::UInt32 Depth;
} Ints;
vtkm::Int64 Raw;
}; // union PackedValue
struct CopyIntoFrameBuffer : public vtkm::worklet::WorkletMapField
{
typedef void ControlSignature(FieldIn<>, FieldIn<>, FieldOut<>);
typedef void ExecutionSignature(_1, _2, _3);
VTKM_CONT
CopyIntoFrameBuffer() {}
VTKM_EXEC
void operator()(const vtkm::Vec<vtkm::Float32, 4>& color,
const vtkm::Float32& depth,
vtkm::Int64& outValue) const
{
PackedValue packed;
packed.Ints.Color = PackColor(color);
packed.Floats.Depth = depth;
outValue = packed.Raw;
}
}; //struct CopyIntoFrameBuffer
template <typename DeviceTag>
class EdgePlotter : public vtkm::worklet::WorkletMapField
{
public:
using AtomicPackedFrameBufferHandle = vtkm::exec::AtomicArray<vtkm::Int64, DeviceTag>;
typedef void ControlSignature(FieldIn<>, WholeArrayIn<>, WholeArrayIn<Scalar>);
typedef void ExecutionSignature(_1, _2, _3);
using InputDomain = _1;
VTKM_CONT
EdgePlotter(const vtkm::Matrix<vtkm::Float32, 4, 4>& worldToProjection,
vtkm::Id width,
vtkm::Id height,
const vtkm::Range& fieldRange,
const ColorMapHandle& colorMap,
const AtomicPackedFrameBufferHandle& frameBuffer,
const vtkm::Range& clippingRange)
: WorldToProjection(worldToProjection)
, Width(width)
, Height(height)
, ColorMap(colorMap.PrepareForInput(DeviceTag()))
, ColorMapSize(vtkm::Float32(colorMap.GetNumberOfValues() - 1))
, FrameBuffer(frameBuffer)
, FieldMin(vtkm::Float32(fieldRange.Min))
{
InverseFieldDelta = 1.0f / vtkm::Float32(fieldRange.Length());
Offset = vtkm::Max(0.03f / vtkm::Float32(clippingRange.Length()), 0.000001f);
}
template <typename CoordinatesPortalType, typename ScalarFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Vec<vtkm::Id, 2>& edgeIndices,
const CoordinatesPortalType& coordsPortal,
const ScalarFieldPortalType& fieldPortal) const
{
vtkm::Id point1Idx = edgeIndices[0];
vtkm::Id point2Idx = edgeIndices[1];
vtkm::Vec<vtkm::Float32, 3> point1 = coordsPortal.Get(edgeIndices[0]);
vtkm::Vec<vtkm::Float32, 3> point2 = coordsPortal.Get(edgeIndices[1]);
TransformWorldToViewport(point1);
TransformWorldToViewport(point2);
vtkm::Float32 x1 = point1[0];
vtkm::Float32 y1 = point1[1];
vtkm::Float32 z1 = point1[2];
vtkm::Float32 x2 = point2[0];
vtkm::Float32 y2 = point2[1];
vtkm::Float32 z2 = point2[2];
// If the line is steep, i.e., the height is greater than the width, then
// transpose the co-ordinates to prevent "holes" in the line. This ensures
// that we pick the co-ordinate which grows at a lesser rate than the other.
bool transposed = vtkm::Abs(y2 - y1) > vtkm::Abs(x2 - x1);
if (transposed)
{
std::swap(x1, y1);
std::swap(x2, y2);
}
// Ensure we are always going from left to right
if (x1 > x2)
{
std::swap(x1, x2);
std::swap(y1, y2);
std::swap(z1, z2);
}
vtkm::Float32 dx = x2 - x1;
vtkm::Float32 dy = y2 - y1;
vtkm::Float32 gradient = (dx == 0.0) ? 1.0f : (dy / dx);
vtkm::Float32 xEnd = vtkm::Round(x1);
vtkm::Float32 yEnd = y1 + gradient * (xEnd - x1);
vtkm::Float32 xGap = ReverseFractionalPart(x1 + 0.5f);
vtkm::Float32 xPxl1 = xEnd, yPxl1 = IntegerPart(yEnd);
vtkm::Float64 point1Field = fieldPortal.Get(point1Idx);
vtkm::Float64 point2Field = fieldPortal.Get(point2Idx);
// Plot first endpoint
vtkm::Vec<vtkm::Float32, 4> color = GetColor(point1Field);
if (transposed)
{
Plot(yPxl1, xPxl1, z1, color, ReverseFractionalPart(yEnd) * xGap);
Plot(yPxl1 + 1, xPxl1, z1, color, FractionalPart(yEnd) * xGap);
}
else
{
Plot(xPxl1, yPxl1, z1, color, ReverseFractionalPart(yEnd) * xGap);
Plot(xPxl1, yPxl1 + 1, z1, color, FractionalPart(yEnd) * xGap);
}
vtkm::Float32 interY = yEnd + gradient;
xEnd = vtkm::Round(x2);
yEnd = y2 + gradient * (xEnd - x2);
xGap = FractionalPart(x2 + 0.5f);
vtkm::Float32 xPxl2 = xEnd, yPxl2 = IntegerPart(yEnd);
// Plot second endpoint
color = GetColor(point2Field);
if (transposed)
{
Plot(yPxl2, xPxl2, z2, color, ReverseFractionalPart(yEnd) * xGap);
Plot(yPxl2 + 1, xPxl2, z2, color, FractionalPart(yEnd) * xGap);
}
else
{
Plot(xPxl2, yPxl2, z2, color, ReverseFractionalPart(yEnd) * xGap);
Plot(xPxl2, yPxl2 + 1, z2, color, FractionalPart(yEnd) * xGap);
}
// Plot rest of the line
if (transposed)
{
for (vtkm::Float32 x = xPxl1 + 1; x <= xPxl2 - 1; ++x)
{
vtkm::Float32 t = IntegerPart(interY);
vtkm::Float32 factor = (x - x1) / dx;
vtkm::Float32 depth = vtkm::Lerp(z1, z2, factor);
vtkm::Float64 fieldValue = vtkm::Lerp(point1Field, point2Field, factor);
color = GetColor(fieldValue);
Plot(t, x, depth, color, ReverseFractionalPart(interY));
Plot(t + 1, x, depth, color, FractionalPart(interY));
interY += gradient;
}
}
else
{
for (vtkm::Float32 x = xPxl1 + 1; x <= xPxl2 - 1; ++x)
{
vtkm::Float32 t = IntegerPart(interY);
vtkm::Float32 factor = (x - x1) / dx;
vtkm::Float32 depth = vtkm::Lerp(z1, z2, factor);
vtkm::Float64 fieldValue = vtkm::Lerp(point1Field, point2Field, factor);
color = GetColor(fieldValue);
Plot(x, t, depth, color, ReverseFractionalPart(interY));
Plot(x, t + 1, depth, color, FractionalPart(interY));
interY += gradient;
}
}
}
private:
using ColorMapPortalConst = typename ColorMapHandle::ExecutionTypes<DeviceTag>::PortalConst;
VTKM_EXEC
void TransformWorldToViewport(vtkm::Vec<vtkm::Float32, 3>& point) const
{
vtkm::Vec<vtkm::Float32, 4> temp(point[0], point[1], point[2], 1.0f);
temp = vtkm::MatrixMultiply(WorldToProjection, temp);
for (vtkm::IdComponent i = 0; i < 3; ++i)
{
point[i] = temp[i] / temp[3];
}
// Scale to canvas width and height
point[0] = (point[0] * 0.5f + 0.5f) * vtkm::Float32(Width);
point[1] = (point[1] * 0.5f + 0.5f) * vtkm::Float32(Height);
// Convert from -1/+1 to 0/+1 range
point[2] = point[2] * 0.5f + 0.5f;
// Offset the point to a bit towards the camera. This is to ensure that the front faces of
// the wireframe wins the z-depth check against the surface render.
point[2] -= Offset;
}
VTKM_EXEC vtkm::Vec<vtkm::Float32, 4> GetColor(vtkm::Float64 fieldValue) const
{
vtkm::Int32 colorIdx =
vtkm::Int32((vtkm::Float32(fieldValue) - FieldMin) * ColorMapSize * InverseFieldDelta);
return ColorMap.Get(colorIdx);
}
VTKM_EXEC
void Plot(vtkm::Float32 x,
vtkm::Float32 y,
vtkm::Float32 depth,
const vtkm::Vec<vtkm::Float32, 4>& color,
vtkm::Float32 intensity) const
{
vtkm::Id xi = static_cast<vtkm::Id>(x), yi = static_cast<vtkm::Id>(y);
if (xi < 0 || xi >= Width || yi < 0 || yi >= Height)
{
return;
}
vtkm::Id index = yi * Width + xi;
PackedValue current, next;
current.Raw = ClearValue;
next.Floats.Depth = depth;
vtkm::Vec<vtkm::Float32, 4> blendedColor;
vtkm::Vec<vtkm::Float32, 4> srcColor;
do
{
UnpackColor(current.Ints.Color, srcColor);
vtkm::Float32 inverseIntensity = (1.0f - intensity);
vtkm::Float32 alpha = srcColor[3] * inverseIntensity;
blendedColor[0] = color[0] * intensity + srcColor[0] * alpha;
blendedColor[1] = color[1] * intensity + srcColor[1] * alpha;
blendedColor[2] = color[2] * intensity + srcColor[2] * alpha;
blendedColor[3] = alpha + intensity;
next.Ints.Color = PackColor(blendedColor);
current.Raw = FrameBuffer.CompareAndSwap(index, next.Raw, current.Raw);
} while (current.Floats.Depth > next.Floats.Depth);
}
vtkm::Matrix<vtkm::Float32, 4, 4> WorldToProjection;
vtkm::Id Width;
vtkm::Id Height;
ColorMapPortalConst ColorMap;
vtkm::Float32 ColorMapSize;
AtomicPackedFrameBufferHandle FrameBuffer;
vtkm::Float32 FieldMin;
vtkm::Float32 InverseFieldDelta;
vtkm::Float32 Offset;
};
struct BufferConverter : public vtkm::worklet::WorkletMapField
{
public:
VTKM_CONT
BufferConverter(vtkm::Vec<vtkm::Float32, 4> backgroundColor)
: BackgroundColor(backgroundColor)
{
}
typedef void ControlSignature(FieldIn<>, ExecObject, ExecObject);
typedef void ExecutionSignature(_1, _2, _3, WorkIndex);
VTKM_EXEC
void operator()(const vtkm::Int64& packedValue,
vtkm::exec::ExecutionWholeArray<vtkm::Float32>& depthBuffer,
vtkm::exec::ExecutionWholeArray<vtkm::Vec<vtkm::Float32, 4>>& colorBuffer,
const vtkm::Id& index) const
{
PackedValue packed;
packed.Raw = packedValue;
float depth = packed.Floats.Depth;
if (depth <= depthBuffer.Get(index))
{
vtkm::Vec<vtkm::Float32, 4> color;
UnpackColor(packed.Ints.Color, color);
colorBuffer.Set(index, color);
depthBuffer.Set(index, depth);
}
}
private:
vtkm::Vec<vtkm::Float32, 4> BackgroundColor;
};
} // namespace
class Wireframer
{
public:
VTKM_CONT
Wireframer(vtkm::rendering::Canvas* canvas, bool showInternalZones, bool isOverlay)
: Canvas(canvas)
, ShowInternalZones(showInternalZones)
, IsOverlay(isOverlay)
{
}
VTKM_CONT
void SetCamera(const vtkm::rendering::Camera& camera) { this->Camera = camera; }
VTKM_CONT
void SetColorMap(const ColorMapHandle& colorMap) { this->ColorMap = colorMap; }
VTKM_CONT
void SetSolidDepthBuffer(const vtkm::cont::ArrayHandle<vtkm::Float32> depthBuffer)
{
this->SolidDepthBuffer = depthBuffer;
}
VTKM_CONT
void SetData(const vtkm::cont::CoordinateSystem& coords,
const IndicesHandle& endPointIndices,
const vtkm::cont::Field& field,
const vtkm::Range& fieldRange)
{
this->Bounds = coords.GetBounds();
this->Coordinates = coords.GetData();
this->PointIndices = endPointIndices;
this->ScalarField = field;
this->ScalarFieldRange = fieldRange;
}
VTKM_CONT
void Render()
{
RenderWithDeviceFunctor functor(this);
vtkm::cont::TryExecute(functor);
}
private:
template <typename DeviceTag>
VTKM_CONT void RenderWithDevice(DeviceTag)
{
if (ScalarField.GetAssociation() != vtkm::cont::Field::ASSOC_POINTS)
{
throw vtkm::cont::ErrorBadValue("Field is not associated with points");
}
vtkm::Matrix<vtkm::Float32, 4, 4> WorldToProjection =
vtkm::MatrixMultiply(Camera.CreateProjectionMatrix(Canvas->GetWidth(), Canvas->GetHeight()),
Camera.CreateViewMatrix());
vtkm::Id width = static_cast<vtkm::Id>(Canvas->GetWidth());
vtkm::Id height = static_cast<vtkm::Id>(Canvas->GetHeight());
vtkm::Id pixelCount = width * height;
FrameBuffer.PrepareForOutput(pixelCount, DeviceTag());
vtkm::Vec<vtkm::Float32, 4> clearColor = Canvas->GetBackgroundColor().Components;
vtkm::UInt32 packedClearColor = PackColor(clearColor);
if (ShowInternalZones && !IsOverlay)
{
using MemSet =
typename vtkm::rendering::Triangulator<DeviceTag>::template MemSet<vtkm::Int64>;
vtkm::Int64 clearValue = (ClearDepth << 32) | packedClearColor;
MemSet memSet(clearValue);
vtkm::worklet::DispatcherMapField<MemSet>(memSet).Invoke(FrameBuffer);
}
else
{
VTKM_ASSERT(SolidDepthBuffer.GetNumberOfValues() == pixelCount);
CopyIntoFrameBuffer bufferCopy;
vtkm::worklet::DispatcherMapField<CopyIntoFrameBuffer>(bufferCopy)
.Invoke(Canvas->GetColorBuffer(), SolidDepthBuffer, FrameBuffer);
}
EdgePlotter<DeviceTag> plotter(WorldToProjection,
width,
height,
ScalarFieldRange,
ColorMap,
FrameBuffer,
Camera.GetClippingRange());
vtkm::worklet::DispatcherMapField<EdgePlotter<DeviceTag>, DeviceTag>(plotter).Invoke(
PointIndices, Coordinates, ScalarField.GetData());
BufferConverter converter(clearColor);
vtkm::worklet::DispatcherMapField<BufferConverter, DeviceTag>(converter).Invoke(
FrameBuffer,
vtkm::exec::ExecutionWholeArray<vtkm::Float32>(Canvas->GetDepthBuffer()),
vtkm::exec::ExecutionWholeArray<vtkm::Vec<vtkm::Float32, 4>>(Canvas->GetColorBuffer()));
}
VTKM_CONT
struct RenderWithDeviceFunctor
{
Wireframer* Renderer;
RenderWithDeviceFunctor(Wireframer* renderer)
: Renderer(renderer)
{
}
template <typename DeviceTag>
VTKM_CONT bool operator()(DeviceTag)
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceTag);
Renderer->RenderWithDevice(DeviceTag());
return true;
}
};
vtkm::Bounds Bounds;
vtkm::rendering::Camera Camera;
vtkm::rendering::Canvas* Canvas;
bool ShowInternalZones;
bool IsOverlay;
ColorMapHandle ColorMap;
vtkm::cont::DynamicArrayHandleCoordinateSystem Coordinates;
IndicesHandle PointIndices;
vtkm::cont::Field ScalarField;
vtkm::Range ScalarFieldRange;
vtkm::cont::ArrayHandle<vtkm::Float32> SolidDepthBuffer;
PackedFrameBufferHandle FrameBuffer;
}; // class Wireframer
}
} //namespace vtkm::rendering
#endif //vtk_m_rendering_Wireframer_h

@ -29,6 +29,7 @@ set(unit_tests
UnitTestMultiMapper.cxx UnitTestMultiMapper.cxx
UnitTestMapperRayTracer.cxx UnitTestMapperRayTracer.cxx
UnitTestMapperVolume.cxx UnitTestMapperVolume.cxx
UnitTestMapperWireframer.cxx
) )
VTKm_unit_tests(SOURCES ${unit_tests}) VTKm_unit_tests(SOURCES ${unit_tests})

@ -0,0 +1,52 @@
//============================================================================
// 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/Testing.h>
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/rendering/MapperWireframer.h>
#include <vtkm/rendering/testing/RenderTest.h>
namespace
{
void RenderTests()
{
typedef vtkm::rendering::MapperWireframer 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.Make3DExplicitDataSet4(), "pointvar", colorTable, "expl3D.pnm");
}
} //namespace
int UnitTestMapperWireframer(int, char* [])
{
return vtkm::cont::testing::Testing::Run(RenderTests);
}