mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-19 02:25:42 +00:00
408 lines
14 KiB
C++
408 lines
14 KiB
C++
//============================================================================
|
|
// 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.
|
|
//============================================================================
|
|
|
|
// vtk-m
|
|
#include <vtkm/cont/ArrayCopy.h>
|
|
#include <vtkm/interop/anari/ANARIMapperPoints.h>
|
|
#include <vtkm/rendering/raytracing/SphereExtractor.h>
|
|
#include <vtkm/worklet/WorkletMapField.h>
|
|
// anari
|
|
#include <anari/anari_cpp/ext/linalg.h>
|
|
|
|
namespace vtkm
|
|
{
|
|
namespace interop
|
|
{
|
|
namespace anari
|
|
{
|
|
|
|
// Worklets ///////////////////////////////////////////////////////////////////
|
|
|
|
class ExtractPointPositions : public vtkm::worklet::WorkletMapField
|
|
{
|
|
public:
|
|
VTKM_CONT
|
|
ExtractPointPositions() = default;
|
|
|
|
using ControlSignature = void(FieldIn, // [in] index
|
|
WholeArrayIn, // [in] point
|
|
WholeArrayOut // [out] point
|
|
);
|
|
using ExecutionSignature = void(InputIndex,
|
|
_1, // [in] index
|
|
_2, // [in] point
|
|
_3 // [out] points
|
|
);
|
|
|
|
template <typename InPointPortalType, typename OutPointPortalType>
|
|
VTKM_EXEC void operator()(const vtkm::Id out_idx,
|
|
const vtkm::Id in_idx,
|
|
const InPointPortalType& points,
|
|
OutPointPortalType& outP) const
|
|
{
|
|
outP.Set(out_idx, static_cast<vtkm::Vec3f_32>(points.Get(in_idx)));
|
|
}
|
|
};
|
|
|
|
// Helper functions ///////////////////////////////////////////////////////////
|
|
|
|
static PointsFieldArrays UnpackFields(FieldSet fields)
|
|
{
|
|
PointsFieldArrays retval;
|
|
|
|
using AttributeHandleT = decltype(retval.Field1);
|
|
|
|
auto makeFieldArray = [](auto field, auto& numComps) -> AttributeHandleT {
|
|
if (field.GetNumberOfValues() == 0)
|
|
return {};
|
|
|
|
auto fieldData = field.GetData();
|
|
numComps = fieldData.GetNumberOfComponentsFlat();
|
|
if (numComps >= 1 && numComps <= 4)
|
|
{
|
|
vtkm::cont::ArrayHandleRuntimeVec<vtkm::Float32> outData(numComps);
|
|
vtkm::cont::ArrayCopyShallowIfPossible(fieldData, outData);
|
|
return outData;
|
|
}
|
|
|
|
return {};
|
|
};
|
|
|
|
retval.Field1 = makeFieldArray(fields[0], retval.NumberOfField1Components);
|
|
retval.Field2 = makeFieldArray(fields[1], retval.NumberOfField2Components);
|
|
retval.Field3 = makeFieldArray(fields[2], retval.NumberOfField3Components);
|
|
retval.Field4 = makeFieldArray(fields[3], retval.NumberOfField4Components);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static PointsArrays UnpackPoints(vtkm::cont::ArrayHandle<vtkm::Id> points,
|
|
vtkm::cont::CoordinateSystem coords)
|
|
{
|
|
PointsArrays retval;
|
|
|
|
const auto numPoints = points.GetNumberOfValues();
|
|
retval.Vertices.Allocate(numPoints);
|
|
vtkm::worklet::DispatcherMapField<ExtractPointPositions>().Invoke(
|
|
points, coords, retval.Vertices);
|
|
|
|
return retval;
|
|
}
|
|
|
|
// ANARIMapperPoints definitions //////////////////////////////////////////////
|
|
|
|
ANARIMapperPoints::ANARIMapperPoints(anari_cpp::Device device,
|
|
const ANARIActor& actor,
|
|
const std::string& name,
|
|
const vtkm::cont::ColorTable& colorTable)
|
|
: ANARIMapper(device, actor, name, colorTable)
|
|
{
|
|
this->Handles = std::make_shared<ANARIMapperPoints::ANARIHandles>();
|
|
this->Handles->Device = device;
|
|
auto& attributes = this->Handles->Parameters.Vertex.Attribute;
|
|
std::fill(attributes.begin(), attributes.end(), nullptr);
|
|
anari_cpp::retain(device, device);
|
|
}
|
|
|
|
ANARIMapperPoints::~ANARIMapperPoints()
|
|
{
|
|
// ensure ANARI handles are released before host memory goes away
|
|
this->Handles.reset();
|
|
}
|
|
|
|
void ANARIMapperPoints::SetActor(const ANARIActor& actor)
|
|
{
|
|
this->ANARIMapper::SetActor(actor);
|
|
this->ConstructArrays(true);
|
|
this->UpdateMaterial();
|
|
}
|
|
|
|
void ANARIMapperPoints::SetMapFieldAsAttribute(bool enabled)
|
|
{
|
|
this->ANARIMapper::SetMapFieldAsAttribute(enabled);
|
|
this->UpdateGeometry();
|
|
this->UpdateMaterial();
|
|
}
|
|
|
|
void ANARIMapperPoints::SetANARIColorMap(anari_cpp::Array1D color,
|
|
anari_cpp::Array1D opacity,
|
|
bool releaseArrays)
|
|
{
|
|
this->GetANARISurface();
|
|
auto s = this->Handles->Sampler;
|
|
if (s)
|
|
{
|
|
auto d = this->GetDevice();
|
|
anari_cpp::setParameter(d, s, "image", color);
|
|
anari_cpp::commitParameters(d, s);
|
|
}
|
|
this->ANARIMapper::SetANARIColorMap(color, opacity, releaseArrays);
|
|
}
|
|
|
|
void ANARIMapperPoints::SetANARIColorMapValueRange(const vtkm::Vec2f_32& valueRange)
|
|
{
|
|
this->GetANARISurface();
|
|
auto s = this->Handles->Sampler;
|
|
if (s)
|
|
{
|
|
auto d = this->GetDevice();
|
|
auto scale =
|
|
anari_cpp::scaling_matrix(anari_cpp::float3(1.f / (valueRange[1] - valueRange[0])));
|
|
auto translation = anari_cpp::translation_matrix(anari_cpp::float3(-valueRange[0], 0, 0));
|
|
anari_cpp::setParameter(d, s, "inTransform", anari_cpp::mul(scale, translation));
|
|
anari_cpp::commitParameters(d, s);
|
|
}
|
|
}
|
|
|
|
anari_cpp::Geometry ANARIMapperPoints::GetANARIGeometry()
|
|
{
|
|
if (this->Handles->Geometry)
|
|
return this->Handles->Geometry;
|
|
|
|
auto d = this->GetDevice();
|
|
this->Handles->Geometry = anari_cpp::newObject<anari_cpp::Geometry>(d, "sphere");
|
|
this->ConstructArrays();
|
|
this->UpdateGeometry();
|
|
|
|
return this->Handles->Geometry;
|
|
}
|
|
|
|
anari_cpp::Surface ANARIMapperPoints::GetANARISurface()
|
|
{
|
|
if (this->Handles->Surface)
|
|
return this->Handles->Surface;
|
|
|
|
auto d = this->GetDevice();
|
|
|
|
this->Handles->Surface = anari_cpp::newObject<anari_cpp::Surface>(d);
|
|
|
|
if (!this->Handles->Material)
|
|
{
|
|
this->Handles->Material = anari_cpp::newObject<anari_cpp::Material>(d, "matte");
|
|
anari_cpp::setParameter(d, this->Handles->Material, "name", this->MakeObjectName("material"));
|
|
}
|
|
|
|
auto s = anari_cpp::newObject<anari_cpp::Sampler>(d, "image1D");
|
|
this->Handles->Sampler = s;
|
|
auto colorArray = anari_cpp::newArray1D(d, ANARI_FLOAT32_VEC4, 3);
|
|
auto* colors = anari_cpp::map<vtkm::Vec4f_32>(d, colorArray);
|
|
colors[0] = vtkm::Vec4f_32(1.f, 0.f, 0.f, 0.f);
|
|
colors[1] = vtkm::Vec4f_32(0.f, 1.f, 0.f, 0.5f);
|
|
colors[2] = vtkm::Vec4f_32(0.f, 0.f, 1.f, 1.f);
|
|
anari_cpp::unmap(d, colorArray);
|
|
anari_cpp::setAndReleaseParameter(d, s, "image", colorArray);
|
|
anari_cpp::setParameter(d, s, "filter", "linear");
|
|
anari_cpp::setParameter(d, s, "wrapMode", "clampToEdge");
|
|
anari_cpp::setParameter(d, s, "name", this->MakeObjectName("colormap"));
|
|
anari_cpp::commitParameters(d, s);
|
|
|
|
this->SetANARIColorMapValueRange(vtkm::Vec2f_32(0.f, 10.f));
|
|
|
|
this->UpdateMaterial();
|
|
|
|
anari_cpp::setParameter(d, this->Handles->Surface, "name", this->MakeObjectName("surface"));
|
|
anari_cpp::setParameter(d, this->Handles->Surface, "geometry", this->GetANARIGeometry());
|
|
anari_cpp::setParameter(d, this->Handles->Surface, "material", this->Handles->Material);
|
|
anari_cpp::commitParameters(d, this->Handles->Surface);
|
|
|
|
return this->Handles->Surface;
|
|
}
|
|
|
|
void ANARIMapperPoints::ConstructArrays(bool regenerate)
|
|
{
|
|
if (regenerate)
|
|
this->Current = false;
|
|
|
|
if (this->Current)
|
|
return;
|
|
|
|
this->Current = true;
|
|
this->Valid = false;
|
|
|
|
this->Handles->ReleaseArrays();
|
|
|
|
const auto& actor = this->GetActor();
|
|
const auto& coords = actor.GetCoordinateSystem();
|
|
|
|
if (coords.GetNumberOfPoints() == 0)
|
|
{
|
|
this->RefreshGroup();
|
|
return;
|
|
}
|
|
|
|
vtkm::Bounds coordBounds = coords.GetBounds();
|
|
// set a default radius
|
|
vtkm::Float64 lx = coordBounds.X.Length();
|
|
vtkm::Float64 ly = coordBounds.Y.Length();
|
|
vtkm::Float64 lz = coordBounds.Z.Length();
|
|
vtkm::Float64 mag = vtkm::Sqrt(lx * lx + ly * ly + lz * lz);
|
|
// same as used in vtk ospray
|
|
constexpr vtkm::Float64 heuristic = 500.;
|
|
auto baseRadius = static_cast<vtkm::Float32>(mag / heuristic);
|
|
|
|
vtkm::rendering::raytracing::SphereExtractor sphereExtractor;
|
|
|
|
sphereExtractor.ExtractCoordinates(coords, baseRadius);
|
|
|
|
auto numPoints = sphereExtractor.GetNumberOfSpheres();
|
|
this->Handles->Parameters.NumPrimitives = static_cast<uint32_t>(numPoints);
|
|
|
|
if (numPoints == 0)
|
|
{
|
|
this->RefreshGroup();
|
|
return;
|
|
}
|
|
|
|
this->PrimaryField = actor.GetPrimaryFieldIndex();
|
|
|
|
auto pts = sphereExtractor.GetPointIds();
|
|
|
|
auto arrays = UnpackPoints(pts, coords);
|
|
auto fieldArrays = UnpackFields(actor.GetFieldSet());
|
|
|
|
arrays.Radii = sphereExtractor.GetRadii();
|
|
auto* p = (vtkm::Vec3f_32*)arrays.Vertices.GetBuffers()[0].ReadPointerHost(*arrays.Token);
|
|
auto* r = (float*)arrays.Radii.GetBuffers()[0].ReadPointerHost(*arrays.Token);
|
|
|
|
auto d = this->GetDevice();
|
|
this->Handles->Parameters.Vertex.Position =
|
|
anari_cpp::newArray1D(d, p, NoopANARIDeleter, nullptr, numPoints);
|
|
this->Handles->Parameters.Vertex.Radius =
|
|
anari_cpp::newArray1D(d, r, NoopANARIDeleter, nullptr, numPoints);
|
|
|
|
auto createANARIArray = [](auto device, auto fieldArray, auto& token) -> anari_cpp::Array1D {
|
|
const auto nv = fieldArray.GetNumberOfValues();
|
|
if (nv == 0)
|
|
return nullptr;
|
|
|
|
anari_cpp::DataType type = ANARI_FLOAT32 + fieldArray.GetNumberOfComponents() - 1;
|
|
const auto& buffers = fieldArray.GetBuffers();
|
|
auto* a = buffers[0].ReadPointerHost(*token);
|
|
if (!a && buffers.size() > 1)
|
|
a = buffers[1].ReadPointerHost(*token);
|
|
|
|
return a ? anariNewArray1D(device, a, NoopANARIDeleter, nullptr, type, nv) : nullptr;
|
|
};
|
|
|
|
this->Handles->Parameters.Vertex.Attribute[0] =
|
|
createANARIArray(d, fieldArrays.Field1, fieldArrays.Token);
|
|
this->Handles->Parameters.Vertex.Attribute[1] =
|
|
createANARIArray(d, fieldArrays.Field2, fieldArrays.Token);
|
|
this->Handles->Parameters.Vertex.Attribute[2] =
|
|
createANARIArray(d, fieldArrays.Field3, fieldArrays.Token);
|
|
this->Handles->Parameters.Vertex.Attribute[3] =
|
|
createANARIArray(d, fieldArrays.Field4, fieldArrays.Token);
|
|
|
|
this->UpdateGeometry();
|
|
this->UpdateMaterial();
|
|
|
|
this->Arrays = arrays;
|
|
this->FieldArrays = fieldArrays;
|
|
this->Valid = true;
|
|
|
|
this->RefreshGroup();
|
|
}
|
|
|
|
void ANARIMapperPoints::UpdateGeometry()
|
|
{
|
|
if (!this->Handles->Geometry)
|
|
return;
|
|
|
|
auto d = this->GetDevice();
|
|
|
|
anari_cpp::unsetParameter(d, this->Handles->Geometry, "vertex.position");
|
|
anari_cpp::unsetParameter(d, this->Handles->Geometry, "vertex.radius");
|
|
anari_cpp::unsetParameter(d, this->Handles->Geometry, "vertex.attribute0");
|
|
anari_cpp::unsetParameter(d, this->Handles->Geometry, "vertex.attribute1");
|
|
anari_cpp::unsetParameter(d, this->Handles->Geometry, "vertex.attribute2");
|
|
anari_cpp::unsetParameter(d, this->Handles->Geometry, "vertex.attribute3");
|
|
|
|
anari_cpp::setParameter(d, this->Handles->Geometry, "name", this->MakeObjectName("geometry"));
|
|
|
|
if (this->Handles->Parameters.Vertex.Position)
|
|
{
|
|
anari_cpp::setParameter(
|
|
d, this->Handles->Geometry, "vertex.position", this->Handles->Parameters.Vertex.Position);
|
|
anari_cpp::setParameter(
|
|
d, this->Handles->Geometry, "vertex.radius", this->Handles->Parameters.Vertex.Radius);
|
|
if (this->GetMapFieldAsAttribute())
|
|
{
|
|
anari_cpp::setParameter(d,
|
|
this->Handles->Geometry,
|
|
"vertex.attribute0",
|
|
this->Handles->Parameters.Vertex.Attribute[0]);
|
|
anari_cpp::setParameter(d,
|
|
this->Handles->Geometry,
|
|
"vertex.attribute1",
|
|
this->Handles->Parameters.Vertex.Attribute[1]);
|
|
anari_cpp::setParameter(d,
|
|
this->Handles->Geometry,
|
|
"vertex.attribute2",
|
|
this->Handles->Parameters.Vertex.Attribute[2]);
|
|
anari_cpp::setParameter(d,
|
|
this->Handles->Geometry,
|
|
"vertex.attribute3",
|
|
this->Handles->Parameters.Vertex.Attribute[3]);
|
|
}
|
|
}
|
|
|
|
anari_cpp::commitParameters(d, this->Handles->Geometry);
|
|
}
|
|
|
|
void ANARIMapperPoints::UpdateMaterial()
|
|
{
|
|
if (!this->Handles->Material)
|
|
return;
|
|
|
|
auto d = this->GetDevice();
|
|
auto s = this->Handles->Sampler;
|
|
auto a = this->Handles->Parameters.Vertex.Attribute[PrimaryField];
|
|
if (s && a && this->GetMapFieldAsAttribute())
|
|
{
|
|
anari_cpp::setParameter(d, s, "inAttribute", AnariMaterialInputString(PrimaryField));
|
|
anari_cpp::commitParameters(d, s);
|
|
anari_cpp::setParameter(d, this->Handles->Material, "color", s);
|
|
}
|
|
else
|
|
anari_cpp::setParameter(d, this->Handles->Material, "color", vtkm::Vec3f_32(1.f));
|
|
|
|
anari_cpp::commitParameters(d, this->Handles->Material);
|
|
}
|
|
|
|
ANARIMapperPoints::ANARIHandles::~ANARIHandles()
|
|
{
|
|
this->ReleaseArrays();
|
|
anari_cpp::release(this->Device, this->Surface);
|
|
anari_cpp::release(this->Device, this->Material);
|
|
anari_cpp::release(this->Device, this->Sampler);
|
|
anari_cpp::release(this->Device, this->Geometry);
|
|
anari_cpp::release(this->Device, this->Device);
|
|
}
|
|
|
|
void ANARIMapperPoints::ANARIHandles::ReleaseArrays()
|
|
{
|
|
anari_cpp::release(this->Device, this->Parameters.Vertex.Position);
|
|
anari_cpp::release(this->Device, this->Parameters.Vertex.Radius);
|
|
anari_cpp::release(this->Device, this->Parameters.Vertex.Attribute[0]);
|
|
anari_cpp::release(this->Device, this->Parameters.Vertex.Attribute[1]);
|
|
anari_cpp::release(this->Device, this->Parameters.Vertex.Attribute[2]);
|
|
anari_cpp::release(this->Device, this->Parameters.Vertex.Attribute[3]);
|
|
this->Parameters.Vertex.Position = nullptr;
|
|
this->Parameters.Vertex.Radius = nullptr;
|
|
this->Parameters.Vertex.Attribute[0] = nullptr;
|
|
this->Parameters.Vertex.Attribute[1] = nullptr;
|
|
this->Parameters.Vertex.Attribute[2] = nullptr;
|
|
this->Parameters.Vertex.Attribute[3] = nullptr;
|
|
}
|
|
|
|
} // namespace anari
|
|
} // namespace interop
|
|
} // namespace vtkm
|