mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-08 13:23:51 +00:00
Merge topic 'anari-rendering'
db4c5c3b9 initial implementation of ANARI rendering support Acked-by: Kitware Robot <kwrobot@kitware.com> Acked-by: Kenneth Moreland <morelandkd@ornl.gov> Merge-request: !2975
This commit is contained in:
commit
ec043d9f7a
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1,3 @@
|
||||
.DS_Store
|
||||
*vscode
|
||||
.anari_deps
|
||||
|
@ -65,7 +65,7 @@
|
||||
- .docker_image
|
||||
|
||||
.ubuntu2004_kokkos: &ubuntu2004_kokkos
|
||||
image: "kitware/vtkm:ci-ubuntu2004_kokkos-20230705"
|
||||
image: "kitware/vtkm:ci-ubuntu2004_kokkos-20230829"
|
||||
extends:
|
||||
- .docker_image
|
||||
|
||||
|
@ -53,6 +53,9 @@ foreach(option IN LISTS options)
|
||||
elseif(no_rendering STREQUAL option)
|
||||
set(VTKm_ENABLE_RENDERING "OFF" CACHE STRING "")
|
||||
|
||||
elseif(anari STREQUAL option)
|
||||
set(VTKm_ENABLE_ANARI "ON" CACHE STRING "")
|
||||
|
||||
elseif(no_testing STREQUAL option)
|
||||
set(VTKm_ENABLE_TESTING "OFF" CACHE STRING "")
|
||||
set(VTKm_ENABLE_TESTING_LIBRARY "OFF" CACHE STRING "")
|
||||
|
@ -52,3 +52,25 @@ RUN mkdir -p /opt/kokkos/build && \
|
||||
cmake -GNinja -DCMAKE_INSTALL_PREFIX=/opt/kokkos -DCMAKE_CXX_FLAGS=-fPIC -DKokkos_ENABLE_SERIAL=ON ../kokkos-$KOKKOS_VERSION &&\
|
||||
ninja all && \
|
||||
ninja install
|
||||
|
||||
# Build and install ANARI SDK
|
||||
WORKDIR /opt/anari/src
|
||||
ARG ANARI_VERSION=0.7.1
|
||||
RUN curl -L https://github.com/KhronosGroup/ANARI-SDK/archive/refs/tags/v$ANARI_VERSION.tar.gz | tar xzv && \
|
||||
cmake -GNinja \
|
||||
-S ANARI-SDK-$ANARI_VERSION \
|
||||
-B build \
|
||||
-DBUILD_CTS=OFF \
|
||||
-DBUILD_EXAMPLES=OFF \
|
||||
-DBUILD_HELIDE_DEVICE=ON \
|
||||
-DBUILD_REMOTE_DEVICE=OFF \
|
||||
-DBUILD_SHARED_LIBS=ON \
|
||||
-DBUILD_TESTING=OFF \
|
||||
-DBUILD_VIEWER=OFF \
|
||||
-DCMAKE_INSTALL_PREFIX=/opt/anari \
|
||||
-DINSTALL_VIEWER_LIBRARY=OFF && \
|
||||
cmake --build build && \
|
||||
cmake --install build && \
|
||||
rm -rf *
|
||||
|
||||
WORKDIR /root
|
||||
|
@ -22,7 +22,8 @@ build:ubuntu2004_kokkos:
|
||||
- .run_automatically
|
||||
variables:
|
||||
CMAKE_BUILD_TYPE: RelWithDebInfo
|
||||
VTKM_SETTINGS: "kokkos+shared+64bit_floats"
|
||||
CMAKE_PREFIX_PATH: "/opt/anari"
|
||||
VTKM_SETTINGS: "kokkos+shared+64bit_floats+rendering+anari"
|
||||
|
||||
test:ubuntu2004_kokkos:
|
||||
tags:
|
||||
|
@ -72,6 +72,7 @@ set(VTKm_ENABLE_OPENMP "@VTKm_ENABLE_OPENMP@")
|
||||
set(VTKm_ENABLE_TBB "@VTKm_ENABLE_TBB@")
|
||||
set(VTKm_ENABLE_LOGGING "@VTKm_ENABLE_LOGGING@")
|
||||
set(VTKm_ENABLE_RENDERING "@VTKm_ENABLE_RENDERING@")
|
||||
set(VTKm_ENABLE_ANARI "@VTKm_ENABLE_ANARI@")
|
||||
set(VTKm_ENABLE_GL_CONTEXT "@VTKm_ENABLE_GL_CONTEXT@")
|
||||
set(VTKm_ENABLE_OSMESA_CONTEXT "@VTKm_ENABLE_OSMESA_CONTEXT@")
|
||||
set(VTKm_ENABLE_EGL_CONTEXT "@VTKm_ENABLE_EGL_CONTEXT@")
|
||||
@ -93,6 +94,7 @@ endif()
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
set(CMAKE_MODULE_PATH_save_vtkm "${CMAKE_MODULE_PATH}")
|
||||
set(PACKAGE_PREFIX_DIR_save_vtkm "${PACKAGE_PREFIX_DIR}")
|
||||
list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_LIST_DIR}")
|
||||
|
||||
if (VTKm_ENABLE_TBB)
|
||||
@ -103,6 +105,16 @@ if (VTKm_ENABLE_TBB)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (VTKm_ENABLE_ANARI)
|
||||
find_dependency(anari)
|
||||
if (NOT anari_FOUND)
|
||||
set(VTKm_FOUND 0)
|
||||
list(APPEND VTKm_NOT_FOUND_REASON "ANARI not found: ${anari_NOT_FOUND_MESSAGE}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(PACKAGE_PREFIX_DIR ${PACKAGE_PREFIX_DIR_save_vtkm})
|
||||
|
||||
# Load the library exports, but only if not compiling VTK-m itself
|
||||
set_and_check(VTKm_CONFIG_DIR "@PACKAGE_VTKm_INSTALL_CONFIG_DIR@")
|
||||
set(VTKM_FROM_INSTALL_DIR FALSE)
|
||||
|
@ -112,6 +112,13 @@ cmake_dependent_option(VTKm_ENABLE_TESTING_LIBRARY "Enable VTKm Testing Library"
|
||||
OFF "NOT VTKm_ENABLE_TESTING;NOT VTKm_ENABLE_BENCHMARKS" ON)
|
||||
mark_as_advanced(VTKm_ENABLE_TESTING_LIBRARY)
|
||||
|
||||
# The ANARI interop library uses a bit of code in vtkm_rendering, so this option
|
||||
# currently requires vtkm_rendering to be built. Eventually this dependency
|
||||
# should go away as vtkm_anari doesn't require applications to use anything from
|
||||
# vtkm_rendering directly.
|
||||
cmake_dependent_option(VTKm_ENABLE_ANARI "Enable ANARI interop support"
|
||||
OFF "VTKm_ENABLE_RENDERING" OFF)
|
||||
|
||||
# We may want to make finer controls on whether libraries/modules get built.
|
||||
# VTK uses the concept of groups for its modules
|
||||
vtkm_option(VTKm_BUILD_ALL_LIBRARIES
|
||||
@ -216,6 +223,7 @@ vtkm_module_force_group(Testing
|
||||
DISABLE_VALUE "DONT_WANT"
|
||||
)
|
||||
vtkm_module_force_group(Benchmarking ENABLE_OPTION VTKm_ENABLE_BENCHMARKS)
|
||||
vtkm_module_force_group(ANARI ENABLE_OPTION VTKm_ENABLE_ANARI)
|
||||
|
||||
# The tutorial requires several common filters. This logic might need to
|
||||
# become more complicated (or less compliated if we decide to always
|
||||
|
3
data/baseline/interop/anari/glyphs.png
Normal file
3
data/baseline/interop/anari/glyphs.png
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:12f5095042fc2bd800d0a556e529103f8e008f10ec112ca0a1acb5b49b283dd7
|
||||
size 367720
|
3
data/baseline/interop/anari/isosurface.png
Normal file
3
data/baseline/interop/anari/isosurface.png
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8d1ff70038dc33f60ea4f002900b6137bc6efb60ca118472b1c4459cc3b67270
|
||||
size 28689
|
3
data/baseline/interop/anari/points.png
Normal file
3
data/baseline/interop/anari/points.png
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:be65f08cf247683224eb8454fc7bfec846b9226fe0c823ac9740c8b06a3b6baf
|
||||
size 23043
|
3
data/baseline/interop/anari/scene-empty-mappers.png
Normal file
3
data/baseline/interop/anari/scene-empty-mappers.png
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:17f87d2e7ea22f0a336a782f89e02e2a3dabb778db236045f1e06dc3a4db433f
|
||||
size 203
|
3
data/baseline/interop/anari/scene.png
Normal file
3
data/baseline/interop/anari/scene.png
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:567eee6acf70a06c58d42afed6c1fa93761ae1a556846c5a9296ef9fd57f98f6
|
||||
size 306635
|
3
data/baseline/interop/anari/volume.png
Normal file
3
data/baseline/interop/anari/volume.png
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:69d625670cdbf38490b7ba2a72d18c5ac57387ca85d5e34d6008ba67d80395f7
|
||||
size 152115
|
128
vtkm/interop/anari/ANARIActor.cxx
Normal file
128
vtkm/interop/anari/ANARIActor.cxx
Normal file
@ -0,0 +1,128 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/interop/anari/ANARIActor.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace interop
|
||||
{
|
||||
namespace anari
|
||||
{
|
||||
|
||||
const char* AnariMaterialInputString(vtkm::IdComponent p)
|
||||
{
|
||||
switch (p)
|
||||
{
|
||||
case 0:
|
||||
default:
|
||||
return "attribute0";
|
||||
case 1:
|
||||
return "attribute1";
|
||||
case 2:
|
||||
return "attribute2";
|
||||
case 3:
|
||||
return "attribute3";
|
||||
}
|
||||
|
||||
return "attribute0";
|
||||
}
|
||||
|
||||
ANARIActor::ANARIActor(const vtkm::cont::UnknownCellSet& cells,
|
||||
const vtkm::cont::CoordinateSystem& coordinates,
|
||||
const vtkm::cont::Field& field0,
|
||||
const vtkm::cont::Field& field1,
|
||||
const vtkm::cont::Field& field2,
|
||||
const vtkm::cont::Field& field3)
|
||||
{
|
||||
this->Data->Cells = cells;
|
||||
this->Data->Coordinates = coordinates;
|
||||
this->Data->Fields[0] = field0;
|
||||
this->Data->Fields[1] = field1;
|
||||
this->Data->Fields[2] = field2;
|
||||
this->Data->Fields[3] = field3;
|
||||
}
|
||||
|
||||
ANARIActor::ANARIActor(const vtkm::cont::UnknownCellSet& cells,
|
||||
const vtkm::cont::CoordinateSystem& coordinates,
|
||||
const FieldSet& f)
|
||||
: ANARIActor(cells, coordinates, f[0], f[1], f[2], f[3])
|
||||
{
|
||||
}
|
||||
|
||||
ANARIActor::ANARIActor(const vtkm::cont::DataSet& dataset,
|
||||
const std::string& field0,
|
||||
const std::string& field1,
|
||||
const std::string& field2,
|
||||
const std::string& field3)
|
||||
{
|
||||
this->Data->Cells = dataset.GetCellSet();
|
||||
if (dataset.GetNumberOfCoordinateSystems() > 0)
|
||||
this->Data->Coordinates = dataset.GetCoordinateSystem();
|
||||
this->Data->Fields[0] = field0.empty() ? vtkm::cont::Field{} : dataset.GetField(field0);
|
||||
this->Data->Fields[1] = field1.empty() ? vtkm::cont::Field{} : dataset.GetField(field1);
|
||||
this->Data->Fields[2] = field2.empty() ? vtkm::cont::Field{} : dataset.GetField(field2);
|
||||
this->Data->Fields[3] = field3.empty() ? vtkm::cont::Field{} : dataset.GetField(field3);
|
||||
}
|
||||
|
||||
const vtkm::cont::UnknownCellSet& ANARIActor::GetCellSet() const
|
||||
{
|
||||
return this->Data->Cells;
|
||||
}
|
||||
|
||||
const vtkm::cont::CoordinateSystem& ANARIActor::GetCoordinateSystem() const
|
||||
{
|
||||
return this->Data->Coordinates;
|
||||
}
|
||||
|
||||
const vtkm::cont::Field& ANARIActor::GetField(vtkm::IdComponent idx) const
|
||||
{
|
||||
return this->Data->Fields[idx < 0 ? GetPrimaryFieldIndex() : idx];
|
||||
}
|
||||
|
||||
FieldSet ANARIActor::GetFieldSet() const
|
||||
{
|
||||
return this->Data->Fields;
|
||||
}
|
||||
|
||||
void ANARIActor::SetPrimaryFieldIndex(vtkm::IdComponent idx)
|
||||
{
|
||||
this->Data->PrimaryField = idx;
|
||||
}
|
||||
|
||||
vtkm::IdComponent ANARIActor::GetPrimaryFieldIndex() const
|
||||
{
|
||||
return this->Data->PrimaryField;
|
||||
}
|
||||
|
||||
vtkm::cont::DataSet ANARIActor::MakeDataSet(bool includeFields) const
|
||||
{
|
||||
vtkm::cont::DataSet dataset;
|
||||
dataset.SetCellSet(GetCellSet());
|
||||
dataset.AddCoordinateSystem(GetCoordinateSystem());
|
||||
if (!includeFields)
|
||||
return dataset;
|
||||
|
||||
auto addField = [&](const vtkm::cont::Field& field) {
|
||||
if (field.GetNumberOfValues() > 0)
|
||||
dataset.AddField(field);
|
||||
};
|
||||
|
||||
addField(this->Data->Fields[0]);
|
||||
addField(this->Data->Fields[1]);
|
||||
addField(this->Data->Fields[2]);
|
||||
addField(this->Data->Fields[3]);
|
||||
|
||||
return dataset;
|
||||
}
|
||||
|
||||
} // namespace anari
|
||||
} // namespace interop
|
||||
} // namespace vtkm
|
108
vtkm/interop/anari/ANARIActor.h
Normal file
108
vtkm/interop/anari/ANARIActor.h
Normal file
@ -0,0 +1,108 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#ifndef vtk_m_interop_anari_ANARIActor_h
|
||||
#define vtk_m_interop_anari_ANARIActor_h
|
||||
|
||||
// vtk-m
|
||||
#include <vtkm/cont/CoordinateSystem.h>
|
||||
#include <vtkm/cont/DataSet.h>
|
||||
#include <vtkm/cont/Field.h>
|
||||
#include <vtkm/cont/UnknownCellSet.h>
|
||||
#include <vtkm/interop/anari/VtkmANARITypes.h>
|
||||
// std
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#include <vtkm/interop/anari/vtkm_anari_export.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace interop
|
||||
{
|
||||
namespace anari
|
||||
{
|
||||
|
||||
/// \brief Convenience type used to represent all the fields in an `ANARIActor`.
|
||||
///
|
||||
using FieldSet = std::array<vtkm::cont::Field, 4>;
|
||||
|
||||
/// \brief Returns the appropriate ANARI attribute string based on field index.
|
||||
///
|
||||
const char* AnariMaterialInputString(vtkm::IdComponent p);
|
||||
|
||||
/// \brief Collects cells, coords, and 0-4 fields for ANARI mappers to consume.
|
||||
///
|
||||
/// `ANARIActor` represents a selected set of cells, coordinates, and fields for
|
||||
/// `ANARIMapper` based mappers to map onto ANARI objects. This class also
|
||||
/// maintains which field is the "main" field, which almost always is the field
|
||||
/// which is used to color the geometry or volume.
|
||||
///
|
||||
/// Mappers creating geometry will generally add all fields as attribute arrays
|
||||
/// if possible, letting applications use more than one field as material inputs
|
||||
/// or data to be color mapped by samplers.
|
||||
///
|
||||
struct VTKM_ANARI_EXPORT ANARIActor
|
||||
{
|
||||
ANARIActor() = default;
|
||||
|
||||
/// @brief Main constructor taking cells, coordinates, and up to 4 fields.
|
||||
///
|
||||
ANARIActor(const vtkm::cont::UnknownCellSet& cells,
|
||||
const vtkm::cont::CoordinateSystem& coordinates,
|
||||
const vtkm::cont::Field& field0 = {},
|
||||
const vtkm::cont::Field& field1 = {},
|
||||
const vtkm::cont::Field& field2 = {},
|
||||
const vtkm::cont::Field& field3 = {});
|
||||
|
||||
/// @brief Convenience constructor when an entire FieldSet already exists.
|
||||
///
|
||||
ANARIActor(const vtkm::cont::UnknownCellSet& cells,
|
||||
const vtkm::cont::CoordinateSystem& coordinates,
|
||||
const FieldSet& fieldset);
|
||||
|
||||
/// @brief Convenience constructor using a dataset + named fields.
|
||||
///
|
||||
ANARIActor(const vtkm::cont::DataSet& dataset,
|
||||
const std::string& field0 = "",
|
||||
const std::string& field1 = "",
|
||||
const std::string& field2 = "",
|
||||
const std::string& field3 = "");
|
||||
|
||||
const vtkm::cont::UnknownCellSet& GetCellSet() const;
|
||||
const vtkm::cont::CoordinateSystem& GetCoordinateSystem() const;
|
||||
const vtkm::cont::Field& GetField(vtkm::IdComponent idx = -1) const;
|
||||
|
||||
FieldSet GetFieldSet() const;
|
||||
|
||||
void SetPrimaryFieldIndex(vtkm::IdComponent idx);
|
||||
vtkm::IdComponent GetPrimaryFieldIndex() const;
|
||||
|
||||
/// @brief Utility to reconstitute a DataSet from the items in the actor.
|
||||
///
|
||||
vtkm::cont::DataSet MakeDataSet(bool includeFields = false) const;
|
||||
|
||||
private:
|
||||
struct ActorData
|
||||
{
|
||||
vtkm::cont::UnknownCellSet Cells;
|
||||
vtkm::cont::CoordinateSystem Coordinates;
|
||||
FieldSet Fields;
|
||||
vtkm::IdComponent PrimaryField{ 0 };
|
||||
};
|
||||
|
||||
std::shared_ptr<ActorData> Data = std::make_shared<ActorData>();
|
||||
};
|
||||
|
||||
} // namespace anari
|
||||
} // namespace interop
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
201
vtkm/interop/anari/ANARIMapper.cxx
Normal file
201
vtkm/interop/anari/ANARIMapper.cxx
Normal file
@ -0,0 +1,201 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/interop/anari/ANARIMapper.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace interop
|
||||
{
|
||||
namespace anari
|
||||
{
|
||||
|
||||
ANARIMapper::ANARIMapper(anari_cpp::Device device,
|
||||
const ANARIActor& actor,
|
||||
const std::string& name,
|
||||
const vtkm::cont::ColorTable& colorTable)
|
||||
: Actor(actor)
|
||||
, ColorTable(colorTable)
|
||||
, Name(name)
|
||||
{
|
||||
this->Handles = std::make_shared<ANARIHandles>();
|
||||
this->Handles->Device = device;
|
||||
anari_cpp::retain(device, device);
|
||||
}
|
||||
|
||||
anari_cpp::Device ANARIMapper::GetDevice() const
|
||||
{
|
||||
return this->Handles->Device;
|
||||
}
|
||||
|
||||
const ANARIActor& ANARIMapper::GetActor() const
|
||||
{
|
||||
return this->Actor;
|
||||
}
|
||||
|
||||
const char* ANARIMapper::GetName() const
|
||||
{
|
||||
return this->Name.c_str();
|
||||
}
|
||||
|
||||
void ANARIMapper::SetActor(const ANARIActor& actor)
|
||||
{
|
||||
this->Actor = actor;
|
||||
}
|
||||
|
||||
void ANARIMapper::SetMapFieldAsAttribute(bool enabled)
|
||||
{
|
||||
this->MapFieldAsAttribute = enabled;
|
||||
}
|
||||
|
||||
bool ANARIMapper::GetMapFieldAsAttribute() const
|
||||
{
|
||||
return this->MapFieldAsAttribute;
|
||||
}
|
||||
|
||||
const vtkm::cont::ColorTable& ANARIMapper::GetColorTable() const
|
||||
{
|
||||
return this->ColorTable;
|
||||
}
|
||||
|
||||
void ANARIMapper::SetANARIColorMap(anari_cpp::Array1D color,
|
||||
anari_cpp::Array1D opacity,
|
||||
bool releaseArrays)
|
||||
{
|
||||
auto d = this->GetDevice();
|
||||
if (releaseArrays)
|
||||
{
|
||||
anari_cpp::release(d, color);
|
||||
anari_cpp::release(d, opacity);
|
||||
}
|
||||
}
|
||||
|
||||
void ANARIMapper::SetANARIColorMapValueRange(const vtkm::Vec2f_32&)
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
void ANARIMapper::SetANARIColorMapOpacityScale(vtkm::Float32)
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
void ANARIMapper::SetName(const char* name)
|
||||
{
|
||||
this->Name = name;
|
||||
}
|
||||
|
||||
void ANARIMapper::SetColorTable(const vtkm::cont::ColorTable& colorTable)
|
||||
{
|
||||
this->ColorTable = colorTable;
|
||||
}
|
||||
|
||||
anari_cpp::Geometry ANARIMapper::GetANARIGeometry()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
anari_cpp::SpatialField ANARIMapper::GetANARISpatialField()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
anari_cpp::Surface ANARIMapper::GetANARISurface()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
anari_cpp::Volume ANARIMapper::GetANARIVolume()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
anari_cpp::Group ANARIMapper::GetANARIGroup()
|
||||
{
|
||||
if (!this->Handles->Group)
|
||||
{
|
||||
auto d = this->GetDevice();
|
||||
this->Handles->Group = anari_cpp::newObject<anari_cpp::Group>(d);
|
||||
this->RefreshGroup();
|
||||
}
|
||||
|
||||
return this->Handles->Group;
|
||||
}
|
||||
|
||||
anari_cpp::Instance ANARIMapper::GetANARIInstance()
|
||||
{
|
||||
if (!this->Handles->Instance)
|
||||
{
|
||||
auto d = this->GetDevice();
|
||||
this->Handles->Instance = anari_cpp::newObject<anari_cpp::Instance>(d, "transform");
|
||||
auto group = this->GetANARIGroup();
|
||||
anari_cpp::setParameter(d, this->Handles->Instance, "group", group);
|
||||
anari_cpp::setParameter(d, this->Handles->Instance, "name", MakeObjectName("instance"));
|
||||
anari_cpp::commitParameters(d, this->Handles->Instance);
|
||||
}
|
||||
|
||||
return this->Handles->Instance;
|
||||
}
|
||||
|
||||
bool ANARIMapper::GroupIsEmpty() const
|
||||
{
|
||||
return !this->Valid;
|
||||
}
|
||||
|
||||
std::string ANARIMapper::MakeObjectName(const char* suffix) const
|
||||
{
|
||||
std::string name = this->GetName();
|
||||
name += '.';
|
||||
name += suffix;
|
||||
return name;
|
||||
}
|
||||
|
||||
void ANARIMapper::RefreshGroup()
|
||||
{
|
||||
if (!this->Handles->Group)
|
||||
return;
|
||||
|
||||
auto d = this->GetDevice();
|
||||
|
||||
anari_cpp::unsetParameter(d, this->Handles->Group, "surface");
|
||||
anari_cpp::unsetParameter(d, this->Handles->Group, "volume");
|
||||
|
||||
auto surface = this->GetANARISurface();
|
||||
auto volume = this->GetANARIVolume();
|
||||
|
||||
if (!this->GroupIsEmpty())
|
||||
{
|
||||
if (surface)
|
||||
anari_cpp::setParameterArray1D(d, this->Handles->Group, "surface", &surface, 1);
|
||||
|
||||
if (volume)
|
||||
anari_cpp::setParameterArray1D(d, this->Handles->Group, "volume", &volume, 1);
|
||||
|
||||
anari_cpp::setParameter(d, this->Handles->Group, "name", MakeObjectName("group"));
|
||||
}
|
||||
|
||||
anari_cpp::commitParameters(d, this->Handles->Group);
|
||||
}
|
||||
|
||||
vtkm::cont::ColorTable& ANARIMapper::GetColorTable()
|
||||
{
|
||||
return this->ColorTable;
|
||||
}
|
||||
|
||||
ANARIMapper::ANARIHandles::~ANARIHandles()
|
||||
{
|
||||
anari_cpp::release(this->Device, this->Group);
|
||||
anari_cpp::release(this->Device, this->Instance);
|
||||
anari_cpp::release(this->Device, this->Device);
|
||||
}
|
||||
|
||||
} // namespace anari
|
||||
} // namespace interop
|
||||
} // namespace vtkm
|
139
vtkm/interop/anari/ANARIMapper.h
Normal file
139
vtkm/interop/anari/ANARIMapper.h
Normal file
@ -0,0 +1,139 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#ifndef vtk_m_interop_anari_ANARIMapper_h
|
||||
#define vtk_m_interop_anari_ANARIMapper_h
|
||||
|
||||
// vtk-m
|
||||
#include <vtkm/cont/ColorTable.h>
|
||||
#include <vtkm/interop/anari/ANARIActor.h>
|
||||
|
||||
#include <vtkm/interop/anari/vtkm_anari_export.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace interop
|
||||
{
|
||||
namespace anari
|
||||
{
|
||||
|
||||
inline void NoopANARIDeleter(const void*, const void*) {}
|
||||
|
||||
/// @brief This is the base class used for all ANARI mappers.
|
||||
///
|
||||
/// This class implements shared functionality of all ANARI mappers. All ANARI
|
||||
/// object handle lifetimes are tied to the lifetime of the mapper, including
|
||||
/// the device. Applications are not intended to ever release handles received
|
||||
/// from the mapper, unless they manually retain the handle. Additionally,
|
||||
/// ANARIMappers will update surface or volume objects if changes occur, such as
|
||||
/// changes to the color map or ANARIActor.
|
||||
struct VTKM_ANARI_EXPORT ANARIMapper
|
||||
{
|
||||
ANARIMapper(anari_cpp::Device device,
|
||||
const ANARIActor& actor = {},
|
||||
const std::string& name = "<noname>",
|
||||
const vtkm::cont::ColorTable& colorTable = vtkm::cont::ColorTable::Preset::Default);
|
||||
virtual ~ANARIMapper() = default;
|
||||
|
||||
anari_cpp::Device GetDevice() const;
|
||||
const ANARIActor& GetActor() const;
|
||||
const char* GetName() const;
|
||||
const vtkm::cont::ColorTable& GetColorTable() const;
|
||||
|
||||
void SetName(const char* name);
|
||||
void SetColorTable(const vtkm::cont::ColorTable& colorTable);
|
||||
|
||||
/// @brief Set the current actor on this mapper.
|
||||
///
|
||||
/// This sets the actor used to create the geometry. When the actor is changed
|
||||
/// the mapper will update all the corresponding ANARI objects accordingly.
|
||||
/// This will not cause new ANARI geometry handles to be made, rather the
|
||||
/// existing handles will be updated to reflect the new actor's data.
|
||||
virtual void SetActor(const ANARIActor& actor);
|
||||
|
||||
/// @brief Set whether fields from `ANARIActor` should end up as geometry attributes.
|
||||
///
|
||||
/// When this is disabled, the mapper will skip creating the data arrays
|
||||
/// associated with fields for when applications only want the raw geometry.
|
||||
/// This defaults to being enabled.
|
||||
virtual void SetMapFieldAsAttribute(bool enabled);
|
||||
bool GetMapFieldAsAttribute() const;
|
||||
|
||||
/// @brief Set color map arrays using raw ANARI array handles.
|
||||
/// @param color Color array used for color mapping.
|
||||
/// @param opacity (unused/deprecated, will remove on future ANARI version)
|
||||
/// @param releaseArrays If true this function will release the hanldes passed in.
|
||||
virtual void SetANARIColorMap(anari_cpp::Array1D color,
|
||||
anari_cpp::Array1D opacity,
|
||||
bool releaseArrays = true);
|
||||
|
||||
/// @brief Set the value range (domain) for the color map.
|
||||
///
|
||||
virtual void SetANARIColorMapValueRange(const vtkm::Vec2f_32& valueRange);
|
||||
|
||||
/// @brief Set a scale factor for opacity (typically used for volumes).
|
||||
///
|
||||
virtual void SetANARIColorMapOpacityScale(vtkm::Float32 opacityScale);
|
||||
|
||||
/// @brief Get the corresponding ANARIGeometry handle from this mapper.
|
||||
///
|
||||
/// NOTE: This handle is not retained, so applications should not release it.
|
||||
virtual anari_cpp::Geometry GetANARIGeometry();
|
||||
|
||||
/// @brief Get the corresponding ANARISpatialField handle from this mapper.
|
||||
///
|
||||
/// NOTE: This handle is not retained, so applications should not release it.
|
||||
virtual anari_cpp::SpatialField GetANARISpatialField();
|
||||
|
||||
/// @brief Get the corresponding ANARISurface handle from this mapper.
|
||||
///
|
||||
/// NOTE: This handle is not retained, so applications should not release it.
|
||||
virtual anari_cpp::Surface GetANARISurface();
|
||||
|
||||
/// @brief Get the corresponding ANARIVolume handle from this mapper.
|
||||
///
|
||||
/// NOTE: This handle is not retained, so applications should not release it.
|
||||
virtual anari_cpp::Volume GetANARIVolume();
|
||||
|
||||
anari_cpp::Group GetANARIGroup();
|
||||
anari_cpp::Instance GetANARIInstance();
|
||||
|
||||
bool GroupIsEmpty() const;
|
||||
|
||||
protected:
|
||||
std::string MakeObjectName(const char* suffix) const;
|
||||
void RefreshGroup();
|
||||
|
||||
vtkm::cont::ColorTable& GetColorTable();
|
||||
|
||||
bool Valid{ false };
|
||||
bool Current{ false };
|
||||
|
||||
private:
|
||||
struct ANARIHandles
|
||||
{
|
||||
anari_cpp::Device Device{ nullptr };
|
||||
anari_cpp::Group Group{ nullptr };
|
||||
anari_cpp::Instance Instance{ nullptr };
|
||||
~ANARIHandles();
|
||||
};
|
||||
|
||||
std::shared_ptr<ANARIHandles> Handles;
|
||||
ANARIActor Actor;
|
||||
vtkm::cont::ColorTable ColorTable;
|
||||
std::string Name;
|
||||
bool MapFieldAsAttribute{ true };
|
||||
};
|
||||
|
||||
} // namespace anari
|
||||
} // namespace interop
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
283
vtkm/interop/anari/ANARIMapperGlyphs.cxx
Normal file
283
vtkm/interop/anari/ANARIMapperGlyphs.cxx
Normal file
@ -0,0 +1,283 @@
|
||||
//============================================================================
|
||||
// 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/rendering/raytracing/SphereExtractor.h"
|
||||
#include <vtkm/VectorAnalysis.h>
|
||||
#include <vtkm/filter/field_conversion/CellAverage.h>
|
||||
#include <vtkm/interop/anari/ANARIMapperGlyphs.h>
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace interop
|
||||
{
|
||||
namespace anari
|
||||
{
|
||||
|
||||
// Worklets ///////////////////////////////////////////////////////////////////
|
||||
|
||||
class GeneratePointGlyphs : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
vtkm::Float32 SizeFactor{ 0.f };
|
||||
bool Offset{ false };
|
||||
|
||||
VTKM_CONT
|
||||
GeneratePointGlyphs(float size = 1.f, bool offset = false)
|
||||
: SizeFactor(size)
|
||||
, Offset(offset)
|
||||
{
|
||||
}
|
||||
|
||||
using ControlSignature = void(FieldIn, WholeArrayIn, WholeArrayOut, WholeArrayOut);
|
||||
using ExecutionSignature = void(InputIndex, _1, _2, _3, _4);
|
||||
|
||||
template <typename InGradientType,
|
||||
typename InPointPortalType,
|
||||
typename OutVertexPortalType,
|
||||
typename OutRadiusPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::Id idx,
|
||||
const InGradientType gradient,
|
||||
const InPointPortalType& points,
|
||||
OutVertexPortalType& vertices,
|
||||
OutRadiusPortalType& radii) const
|
||||
{
|
||||
auto ng = vtkm::Normal(static_cast<vtkm::Vec3f_32>(gradient));
|
||||
auto pt = points.Get(idx);
|
||||
auto v0 = pt + ng * this->SizeFactor;
|
||||
auto v1 = pt + ng * -this->SizeFactor;
|
||||
if (this->Offset)
|
||||
{
|
||||
vertices.Set(4 * idx + 0, pt);
|
||||
vertices.Set(4 * idx + 1, v1);
|
||||
vertices.Set(4 * idx + 2, v1);
|
||||
vertices.Set(4 * idx + 3, v1 - (this->SizeFactor * ng));
|
||||
}
|
||||
else
|
||||
{
|
||||
vertices.Set(4 * idx + 0, v0);
|
||||
vertices.Set(4 * idx + 1, pt);
|
||||
vertices.Set(4 * idx + 2, pt);
|
||||
vertices.Set(4 * idx + 3, v1);
|
||||
}
|
||||
radii.Set(4 * idx + 0, this->SizeFactor / 8);
|
||||
radii.Set(4 * idx + 1, this->SizeFactor / 8);
|
||||
radii.Set(4 * idx + 2, this->SizeFactor / 4);
|
||||
radii.Set(4 * idx + 3, 0.f);
|
||||
}
|
||||
};
|
||||
|
||||
// Helper functions ///////////////////////////////////////////////////////////
|
||||
|
||||
static GlyphArrays MakeGlyphs(vtkm::cont::Field gradients,
|
||||
vtkm::cont::UnknownCellSet cells,
|
||||
vtkm::cont::CoordinateSystem coords,
|
||||
float glyphSize,
|
||||
bool offset)
|
||||
{
|
||||
const auto numGlyphs = gradients.GetNumberOfValues();
|
||||
|
||||
GlyphArrays retval;
|
||||
|
||||
retval.Vertices.Allocate(numGlyphs * 4);
|
||||
retval.Radii.Allocate(numGlyphs * 4);
|
||||
|
||||
GeneratePointGlyphs worklet(glyphSize, offset);
|
||||
vtkm::worklet::DispatcherMapField<GeneratePointGlyphs> dispatch(worklet);
|
||||
|
||||
if (gradients.IsPointField())
|
||||
dispatch.Invoke(gradients, coords, retval.Vertices, retval.Radii);
|
||||
else
|
||||
{
|
||||
vtkm::cont::DataSet centersInput;
|
||||
centersInput.AddCoordinateSystem(coords);
|
||||
centersInput.SetCellSet(cells);
|
||||
|
||||
vtkm::filter::field_conversion::CellAverage filter;
|
||||
filter.SetUseCoordinateSystemAsField(true);
|
||||
filter.SetOutputFieldName("Centers");
|
||||
auto centersOutput = filter.Execute(centersInput);
|
||||
|
||||
auto resolveField = [&](const auto& concreteField) {
|
||||
dispatch.Invoke(gradients, concreteField, retval.Vertices, retval.Radii);
|
||||
};
|
||||
centersOutput.GetField("Centers")
|
||||
.GetData()
|
||||
.CastAndCallForTypesWithFloatFallback<vtkm::TypeListFieldVec3,
|
||||
vtkm::List<vtkm::cont::StorageTagBasic>>(resolveField);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// ANARIMapperGlyphs definitions //////////////////////////////////////////////
|
||||
|
||||
ANARIMapperGlyphs::ANARIMapperGlyphs(anari_cpp::Device device,
|
||||
const ANARIActor& actor,
|
||||
const char* name,
|
||||
const vtkm::cont::ColorTable& colorTable)
|
||||
: ANARIMapper(device, actor, name, colorTable)
|
||||
{
|
||||
this->Handles = std::make_shared<ANARIMapperGlyphs::ANARIHandles>();
|
||||
this->Handles->Device = device;
|
||||
anari_cpp::retain(device, device);
|
||||
}
|
||||
|
||||
ANARIMapperGlyphs::~ANARIMapperGlyphs()
|
||||
{
|
||||
// ensure ANARI handles are released before host memory goes away
|
||||
this->Handles.reset();
|
||||
}
|
||||
|
||||
void ANARIMapperGlyphs::SetActor(const ANARIActor& actor)
|
||||
{
|
||||
this->ANARIMapper::SetActor(actor);
|
||||
this->ConstructArrays(true);
|
||||
}
|
||||
|
||||
void ANARIMapperGlyphs::SetOffsetGlyphs(bool enabled)
|
||||
{
|
||||
this->Offset = enabled;
|
||||
}
|
||||
|
||||
anari_cpp::Geometry ANARIMapperGlyphs::GetANARIGeometry()
|
||||
{
|
||||
if (this->Handles->Geometry)
|
||||
return this->Handles->Geometry;
|
||||
|
||||
auto d = this->GetDevice();
|
||||
this->Handles->Geometry = anari_cpp::newObject<anari_cpp::Geometry>(d, "cone");
|
||||
this->ConstructArrays();
|
||||
this->UpdateGeometry();
|
||||
return this->Handles->Geometry;
|
||||
}
|
||||
|
||||
anari_cpp::Surface ANARIMapperGlyphs::GetANARISurface()
|
||||
{
|
||||
if (this->Handles->Surface)
|
||||
return this->Handles->Surface;
|
||||
|
||||
auto d = this->GetDevice();
|
||||
|
||||
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"));
|
||||
}
|
||||
|
||||
anari_cpp::commitParameters(d, this->Handles->Material);
|
||||
|
||||
this->Handles->Surface = anari_cpp::newObject<anari_cpp::Surface>(d);
|
||||
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 ANARIMapperGlyphs::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();
|
||||
const auto& cells = actor.GetCellSet();
|
||||
const auto& field = actor.GetField();
|
||||
|
||||
auto numGlyphs = field.GetNumberOfValues();
|
||||
|
||||
if (numGlyphs == 0)
|
||||
{
|
||||
this->RefreshGroup();
|
||||
return;
|
||||
}
|
||||
|
||||
vtkm::Bounds coordBounds = coords.GetBounds();
|
||||
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);
|
||||
constexpr vtkm::Float64 heuristic = 300.;
|
||||
auto glyphSize = static_cast<vtkm::Float32>(mag / heuristic);
|
||||
|
||||
auto arrays = MakeGlyphs(field, cells, coords, glyphSize, Offset);
|
||||
|
||||
auto* v = (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, v, NoopANARIDeleter, nullptr, arrays.Vertices.GetNumberOfValues());
|
||||
this->Handles->Parameters.Vertex.Radius =
|
||||
anari_cpp::newArray1D(d, r, NoopANARIDeleter, nullptr, arrays.Radii.GetNumberOfValues());
|
||||
this->Handles->Parameters.NumPrimitives = numGlyphs;
|
||||
|
||||
this->UpdateGeometry();
|
||||
|
||||
this->Arrays = arrays;
|
||||
this->Valid = true;
|
||||
|
||||
this->RefreshGroup();
|
||||
}
|
||||
|
||||
void ANARIMapperGlyphs::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::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);
|
||||
anari_cpp::setParameter(d, this->Handles->Geometry, "caps", "both");
|
||||
}
|
||||
|
||||
anari_cpp::commitParameters(d, this->Handles->Geometry);
|
||||
}
|
||||
|
||||
ANARIMapperGlyphs::ANARIHandles::~ANARIHandles()
|
||||
{
|
||||
this->ReleaseArrays();
|
||||
anari_cpp::release(this->Device, this->Surface);
|
||||
anari_cpp::release(this->Device, this->Material);
|
||||
anari_cpp::release(this->Device, this->Geometry);
|
||||
anari_cpp::release(this->Device, this->Device);
|
||||
}
|
||||
|
||||
void ANARIMapperGlyphs::ANARIHandles::ReleaseArrays()
|
||||
{
|
||||
anari_cpp::release(this->Device, this->Parameters.Vertex.Position);
|
||||
anari_cpp::release(this->Device, this->Parameters.Vertex.Radius);
|
||||
this->Parameters.Vertex.Position = nullptr;
|
||||
this->Parameters.Vertex.Radius = nullptr;
|
||||
}
|
||||
|
||||
} // namespace anari
|
||||
} // namespace interop
|
||||
} // namespace vtkm
|
118
vtkm/interop/anari/ANARIMapperGlyphs.h
Normal file
118
vtkm/interop/anari/ANARIMapperGlyphs.h
Normal file
@ -0,0 +1,118 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#ifndef vtk_m_interop_anari_ANARIMapperGlyphs_h
|
||||
#define vtk_m_interop_anari_ANARIMapperGlyphs_h
|
||||
|
||||
#include <vtkm/interop/anari/ANARIMapper.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace interop
|
||||
{
|
||||
namespace anari
|
||||
{
|
||||
|
||||
/// @brief Raw ANARI arrays and parameter values set on the `ANARIGeometry`.
|
||||
///
|
||||
struct GlyphsParameters
|
||||
{
|
||||
struct VertexData
|
||||
{
|
||||
anari_cpp::Array1D Position{ nullptr };
|
||||
anari_cpp::Array1D Radius{ nullptr };
|
||||
} Vertex{};
|
||||
|
||||
unsigned int NumPrimitives{ 0 };
|
||||
};
|
||||
|
||||
/// @brief VTK-m data arrays underlying the `ANARIArray` handles created by the mapper.
|
||||
///
|
||||
struct GlyphArrays
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f_32> Vertices;
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32> Radii;
|
||||
std::shared_ptr<vtkm::cont::Token> Token{ new vtkm::cont::Token };
|
||||
};
|
||||
|
||||
/// @brief Mapper which turns vector data into arrow glyphs.
|
||||
///
|
||||
/// This mapper creates ANARI `cone` geometry for the primary field in the
|
||||
/// provided `ANARIActor`.
|
||||
struct VTKM_ANARI_EXPORT ANARIMapperGlyphs : public ANARIMapper
|
||||
{
|
||||
/// @brief Constructor
|
||||
///
|
||||
ANARIMapperGlyphs(
|
||||
anari_cpp::Device device,
|
||||
const ANARIActor& actor = {},
|
||||
const char* name = "<glyphs>",
|
||||
const vtkm::cont::ColorTable& colorTable = vtkm::cont::ColorTable::Preset::Default);
|
||||
|
||||
/// @brief Destructor
|
||||
///
|
||||
~ANARIMapperGlyphs() override;
|
||||
|
||||
/// @brief Set the current actor on this mapper.
|
||||
///
|
||||
/// This sets the actor used to create the geometry. When the actor is changed
|
||||
/// the mapper will update all the corresponding ANARI objects accordingly.
|
||||
/// This will not cause new ANARI geometry handles to be made, rather the
|
||||
/// existing handles will be updated to reflect the new actor's data.
|
||||
void SetActor(const ANARIActor& actor) override;
|
||||
|
||||
/// @brief Offset the glyph in the direction of the vector at each point.
|
||||
///
|
||||
/// This will cause the mapper to offset the glyph, making the arrow appear to
|
||||
/// be coming out of the point instead of going through it. This is useful for
|
||||
/// visualizing things like surface normals on a mesh.
|
||||
void SetOffsetGlyphs(bool enabled);
|
||||
|
||||
/// @brief Get the corresponding ANARIGeometry handle from this mapper.
|
||||
///
|
||||
/// NOTE: This handle is not retained, so applications should not release it.
|
||||
anari_cpp::Geometry GetANARIGeometry() override;
|
||||
|
||||
/// @brief Get the corresponding ANARISurface handle from this mapper.
|
||||
///
|
||||
/// NOTE: This handle is not retained, so applications should not release it.
|
||||
anari_cpp::Surface GetANARISurface() override;
|
||||
|
||||
private:
|
||||
/// @brief Do the work to construct the basic ANARI arrays for the ANARIGeometry.
|
||||
/// @param regenerate Force the position/radius arrays are regenerated.
|
||||
///
|
||||
void ConstructArrays(bool regenerate = false);
|
||||
/// @brief Update ANARIGeometry object with the latest data from the actor.
|
||||
void UpdateGeometry();
|
||||
|
||||
/// @brief Container of all relevant ANARI scene object handles.
|
||||
struct ANARIHandles
|
||||
{
|
||||
anari_cpp::Device Device{ nullptr };
|
||||
anari_cpp::Geometry Geometry{ nullptr };
|
||||
anari_cpp::Material Material{ nullptr };
|
||||
anari_cpp::Surface Surface{ nullptr };
|
||||
GlyphsParameters Parameters;
|
||||
~ANARIHandles();
|
||||
void ReleaseArrays();
|
||||
};
|
||||
|
||||
std::shared_ptr<ANARIHandles> Handles;
|
||||
|
||||
bool Offset{ false };
|
||||
GlyphArrays Arrays;
|
||||
};
|
||||
|
||||
} // namespace anari
|
||||
} // namespace interop
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
407
vtkm/interop/anari/ANARIMapperPoints.cxx
Normal file
407
vtkm/interop/anari/ANARIMapperPoints.cxx
Normal file
@ -0,0 +1,407 @@
|
||||
//============================================================================
|
||||
// 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
|
137
vtkm/interop/anari/ANARIMapperPoints.h
Normal file
137
vtkm/interop/anari/ANARIMapperPoints.h
Normal file
@ -0,0 +1,137 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#ifndef vtk_m_interop_anari_ANARIMapperPoints_h
|
||||
#define vtk_m_interop_anari_ANARIMapperPoints_h
|
||||
|
||||
#include <vtkm/cont/ArrayHandleRuntimeVec.h>
|
||||
#include <vtkm/interop/anari/ANARIMapper.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace interop
|
||||
{
|
||||
namespace anari
|
||||
{
|
||||
|
||||
/// @brief Raw ANARI arrays and parameter values set on the `ANARIGeometry`.
|
||||
///
|
||||
struct PointsParameters
|
||||
{
|
||||
struct VertexData
|
||||
{
|
||||
anari_cpp::Array1D Position{ nullptr };
|
||||
anari_cpp::Array1D Radius{ nullptr };
|
||||
std::array<anari_cpp::Array1D, 4> Attribute;
|
||||
} Vertex{};
|
||||
|
||||
unsigned int NumPrimitives{ 0 };
|
||||
};
|
||||
|
||||
/// @brief VTK-m data arrays underlying the `ANARIArray` handles created by the mapper.
|
||||
///
|
||||
struct PointsArrays
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f_32> Vertices;
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32> Radii;
|
||||
std::shared_ptr<vtkm::cont::Token> Token{ new vtkm::cont::Token };
|
||||
};
|
||||
|
||||
/// @brief VTK-m data arrays underlying the `ANARIArray` handles created by the mapper for field attributes.
|
||||
///
|
||||
struct PointsFieldArrays
|
||||
{
|
||||
vtkm::cont::ArrayHandleRuntimeVec<vtkm::Float32> Field1;
|
||||
int NumberOfField1Components{ 1 };
|
||||
vtkm::cont::ArrayHandleRuntimeVec<vtkm::Float32> Field2;
|
||||
int NumberOfField2Components{ 1 };
|
||||
vtkm::cont::ArrayHandleRuntimeVec<vtkm::Float32> Field3;
|
||||
int NumberOfField3Components{ 1 };
|
||||
vtkm::cont::ArrayHandleRuntimeVec<vtkm::Float32> Field4;
|
||||
int NumberOfField4Components{ 1 };
|
||||
std::shared_ptr<vtkm::cont::Token> Token{ new vtkm::cont::Token };
|
||||
};
|
||||
|
||||
/// @brief Mapper which turns each point into ANARI `sphere` geometry.
|
||||
///
|
||||
/// NOTE: This mapper will color map values that are 1/2/3/4 component Float32
|
||||
/// fields, otherwise they will be ignored.
|
||||
struct VTKM_ANARI_EXPORT ANARIMapperPoints : public ANARIMapper
|
||||
{
|
||||
/// @brief Constructor
|
||||
///
|
||||
ANARIMapperPoints(
|
||||
anari_cpp::Device device,
|
||||
const ANARIActor& actor = {},
|
||||
const std::string& name = "<points>",
|
||||
const vtkm::cont::ColorTable& colorTable = vtkm::cont::ColorTable::Preset::Default);
|
||||
|
||||
/// @brief Destructor
|
||||
///
|
||||
~ANARIMapperPoints() override;
|
||||
|
||||
/// @brief Set the current actor on this mapper.
|
||||
///
|
||||
/// See `ANARIMapper` for more detail.
|
||||
void SetActor(const ANARIActor& actor) override;
|
||||
|
||||
/// @brief Set whether fields from `ANARIActor` should end up as geometry attributes.
|
||||
///
|
||||
/// See `ANARIMapper` for more detail.
|
||||
void SetMapFieldAsAttribute(bool enabled) override;
|
||||
|
||||
/// @brief Set color map arrays using raw ANARI array handles.
|
||||
///
|
||||
/// See `ANARIMapper` for more detail.
|
||||
void SetANARIColorMap(anari_cpp::Array1D color,
|
||||
anari_cpp::Array1D opacity,
|
||||
bool releaseArrays = true) override;
|
||||
|
||||
/// @brief Set the value range (domain) for the color map.
|
||||
///
|
||||
void SetANARIColorMapValueRange(const vtkm::Vec2f_32& valueRange) override;
|
||||
|
||||
anari_cpp::Geometry GetANARIGeometry() override;
|
||||
anari_cpp::Surface GetANARISurface() override;
|
||||
|
||||
private:
|
||||
/// @brief Do the work to construct the basic ANARI arrays for the ANARIGeometry.
|
||||
/// @param regenerate Force the position/radius arrays are regenerated.
|
||||
///
|
||||
void ConstructArrays(bool regenerate = false);
|
||||
/// @brief Update ANARIGeometry object with the latest data from the actor.
|
||||
void UpdateGeometry();
|
||||
/// @brief Update ANARIMaterial object with the latest data from the actor.
|
||||
void UpdateMaterial();
|
||||
|
||||
/// @brief Container of all relevant ANARI scene object handles.
|
||||
struct ANARIHandles
|
||||
{
|
||||
anari_cpp::Device Device{ nullptr };
|
||||
anari_cpp::Geometry Geometry{ nullptr };
|
||||
anari_cpp::Sampler Sampler{ nullptr };
|
||||
anari_cpp::Material Material{ nullptr };
|
||||
anari_cpp::Surface Surface{ nullptr };
|
||||
PointsParameters Parameters;
|
||||
~ANARIHandles();
|
||||
void ReleaseArrays();
|
||||
};
|
||||
|
||||
std::shared_ptr<ANARIHandles> Handles;
|
||||
vtkm::IdComponent PrimaryField{ 0 };
|
||||
PointsArrays Arrays;
|
||||
PointsFieldArrays FieldArrays;
|
||||
};
|
||||
|
||||
} // namespace anari
|
||||
} // namespace interop
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
611
vtkm/interop/anari/ANARIMapperTriangles.cxx
Normal file
611
vtkm/interop/anari/ANARIMapperTriangles.cxx
Normal file
@ -0,0 +1,611 @@
|
||||
//============================================================================
|
||||
// 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/filter/vector_analysis/SurfaceNormals.h>
|
||||
#include <vtkm/interop/anari/ANARIMapperTriangles.h>
|
||||
#include <vtkm/rendering/raytracing/TriangleExtractor.h>
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
// std
|
||||
#include <numeric>
|
||||
// anari
|
||||
#include <anari/anari_cpp/ext/linalg.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace interop
|
||||
{
|
||||
namespace anari
|
||||
{
|
||||
|
||||
// Worklets ///////////////////////////////////////////////////////////////////
|
||||
|
||||
class ExtractTriangleFields : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
bool PopulateField1{ false };
|
||||
bool PopulateField2{ false };
|
||||
bool PopulateField3{ false };
|
||||
bool PopulateField4{ false };
|
||||
vtkm::Range Field1Range;
|
||||
vtkm::Range Field2Range;
|
||||
vtkm::Range Field3Range;
|
||||
vtkm::Range Field4Range;
|
||||
|
||||
VTKM_CONT
|
||||
ExtractTriangleFields(bool emptyField1,
|
||||
bool emptyField2,
|
||||
bool emptyField3,
|
||||
bool emptyField4,
|
||||
vtkm::Range field1Range,
|
||||
vtkm::Range field2Range,
|
||||
vtkm::Range field3Range,
|
||||
vtkm::Range field4Range)
|
||||
: PopulateField1(!emptyField1)
|
||||
, PopulateField2(!emptyField2)
|
||||
, PopulateField3(!emptyField3)
|
||||
, PopulateField4(!emptyField4)
|
||||
, Field1Range(field1Range)
|
||||
, Field2Range(field2Range)
|
||||
, Field3Range(field3Range)
|
||||
, Field4Range(field4Range)
|
||||
{
|
||||
}
|
||||
|
||||
using ControlSignature = void(FieldIn,
|
||||
WholeArrayIn, // [in] field1
|
||||
WholeArrayIn, // [in] field2
|
||||
WholeArrayIn, // [in] field3
|
||||
WholeArrayIn, // [in] field4
|
||||
WholeArrayOut, // [out] field1
|
||||
WholeArrayOut, // [out] field2
|
||||
WholeArrayOut, // [out] field3
|
||||
WholeArrayOut // [out] field4
|
||||
);
|
||||
using ExecutionSignature = void(InputIndex,
|
||||
_1, // [in] indices
|
||||
_2, // [in] field1
|
||||
_3, // [in] field2
|
||||
_4, // [in] field3
|
||||
_5, // [in] field4
|
||||
_6, // [out] field1
|
||||
_7, // [out] field2
|
||||
_8, // [out] field3
|
||||
_9 // [out] field4
|
||||
);
|
||||
|
||||
template <typename FieldPortalType, typename OutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::Id idx,
|
||||
const vtkm::Id4 indices,
|
||||
const FieldPortalType& field1,
|
||||
const FieldPortalType& field2,
|
||||
const FieldPortalType& field3,
|
||||
const FieldPortalType& field4,
|
||||
OutFieldPortalType& outF1,
|
||||
OutFieldPortalType& outF2,
|
||||
OutFieldPortalType& outF3,
|
||||
OutFieldPortalType& outF4) const
|
||||
{
|
||||
const auto i0 = indices[1];
|
||||
const auto i1 = indices[2];
|
||||
const auto i2 = indices[3];
|
||||
if (this->PopulateField1)
|
||||
{
|
||||
outF1.Set(3 * idx + 0, static_cast<vtkm::Float32>(field1.Get(i0)));
|
||||
outF1.Set(3 * idx + 1, static_cast<vtkm::Float32>(field1.Get(i1)));
|
||||
outF1.Set(3 * idx + 2, static_cast<vtkm::Float32>(field1.Get(i2)));
|
||||
}
|
||||
if (this->PopulateField2)
|
||||
{
|
||||
outF2.Set(3 * idx + 0, static_cast<vtkm::Float32>(field2.Get(i0)));
|
||||
outF2.Set(3 * idx + 1, static_cast<vtkm::Float32>(field2.Get(i1)));
|
||||
outF2.Set(3 * idx + 2, static_cast<vtkm::Float32>(field2.Get(i2)));
|
||||
}
|
||||
if (this->PopulateField3)
|
||||
{
|
||||
outF3.Set(3 * idx + 0, static_cast<vtkm::Float32>(field3.Get(i0)));
|
||||
outF3.Set(3 * idx + 1, static_cast<vtkm::Float32>(field3.Get(i1)));
|
||||
outF3.Set(3 * idx + 2, static_cast<vtkm::Float32>(field3.Get(i2)));
|
||||
}
|
||||
if (this->PopulateField4)
|
||||
{
|
||||
outF4.Set(3 * idx + 0, static_cast<vtkm::Float32>(field4.Get(i0)));
|
||||
outF4.Set(3 * idx + 1, static_cast<vtkm::Float32>(field4.Get(i1)));
|
||||
outF4.Set(3 * idx + 2, static_cast<vtkm::Float32>(field4.Get(i2)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ExtractTriangleVerticesAndNormals : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
bool ExtractNormals{ false };
|
||||
|
||||
VTKM_CONT
|
||||
ExtractTriangleVerticesAndNormals(bool withNormals)
|
||||
: ExtractNormals(withNormals)
|
||||
{
|
||||
}
|
||||
|
||||
using ControlSignature = void(FieldIn,
|
||||
WholeArrayIn, // [in] points
|
||||
WholeArrayIn, // [in] normals
|
||||
WholeArrayOut, // [out] points
|
||||
WholeArrayOut // [out] normals
|
||||
);
|
||||
using ExecutionSignature = void(InputIndex,
|
||||
_1, // [in] indices
|
||||
_2, // [in] points
|
||||
_3, // [in] normals
|
||||
_4, // [out] points
|
||||
_5 // [out] normals
|
||||
);
|
||||
|
||||
template <typename PointPortalType,
|
||||
typename NormalPortalType,
|
||||
typename OutPointsPortalType,
|
||||
typename OutNormalsPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::Id idx,
|
||||
const vtkm::Id4 indices,
|
||||
const PointPortalType& points,
|
||||
const NormalPortalType& normals,
|
||||
OutPointsPortalType& outP,
|
||||
OutNormalsPortalType& outN) const
|
||||
{
|
||||
const auto i0 = indices[1];
|
||||
const auto i1 = indices[2];
|
||||
const auto i2 = indices[3];
|
||||
outP.Set(3 * idx + 0, static_cast<vtkm::Vec3f_32>(points.Get(i0)));
|
||||
outP.Set(3 * idx + 1, static_cast<vtkm::Vec3f_32>(points.Get(i1)));
|
||||
outP.Set(3 * idx + 2, static_cast<vtkm::Vec3f_32>(points.Get(i2)));
|
||||
if (this->ExtractNormals)
|
||||
{
|
||||
outN.Set(3 * idx + 0, static_cast<vtkm::Vec3f_32>(normals.Get(i0)));
|
||||
outN.Set(3 * idx + 1, static_cast<vtkm::Vec3f_32>(normals.Get(i1)));
|
||||
outN.Set(3 * idx + 2, static_cast<vtkm::Vec3f_32>(normals.Get(i2)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Helper functions ///////////////////////////////////////////////////////////
|
||||
|
||||
static TriangleFieldArrays UnpackFields(vtkm::cont::ArrayHandle<vtkm::Id4> tris,
|
||||
FieldSet fields,
|
||||
vtkm::Range range)
|
||||
{
|
||||
TriangleFieldArrays retval;
|
||||
|
||||
const auto numTris = tris.GetNumberOfValues();
|
||||
|
||||
using AttributeHandleT = decltype(retval.Field1);
|
||||
|
||||
auto isFieldEmpty = [](const vtkm::cont::Field& f) -> bool {
|
||||
return f.GetNumberOfValues() == 0 || f.GetData().GetNumberOfComponentsFlat() != 1 ||
|
||||
!f.GetData().CanConvert<AttributeHandleT>();
|
||||
};
|
||||
|
||||
const bool emptyField1 = isFieldEmpty(fields[0]);
|
||||
const bool emptyField2 = isFieldEmpty(fields[1]);
|
||||
const bool emptyField3 = isFieldEmpty(fields[2]);
|
||||
const bool emptyField4 = isFieldEmpty(fields[3]);
|
||||
|
||||
auto field1 =
|
||||
emptyField1 ? AttributeHandleT{} : fields[0].GetData().AsArrayHandle<AttributeHandleT>();
|
||||
auto field2 =
|
||||
emptyField2 ? AttributeHandleT{} : fields[1].GetData().AsArrayHandle<AttributeHandleT>();
|
||||
auto field3 =
|
||||
emptyField3 ? AttributeHandleT{} : fields[2].GetData().AsArrayHandle<AttributeHandleT>();
|
||||
auto field4 =
|
||||
emptyField4 ? AttributeHandleT{} : fields[3].GetData().AsArrayHandle<AttributeHandleT>();
|
||||
|
||||
vtkm::Range field1Range = range;
|
||||
vtkm::Range field2Range = range;
|
||||
vtkm::Range field3Range = range;
|
||||
vtkm::Range field4Range = range;
|
||||
|
||||
if (!emptyField1)
|
||||
{
|
||||
retval.Field1.Allocate(numTris * 3);
|
||||
}
|
||||
if (!emptyField2)
|
||||
{
|
||||
retval.Field2.Allocate(numTris * 3);
|
||||
}
|
||||
if (!emptyField3)
|
||||
{
|
||||
retval.Field3.Allocate(numTris * 3);
|
||||
}
|
||||
if (!emptyField4)
|
||||
{
|
||||
retval.Field4.Allocate(numTris * 3);
|
||||
}
|
||||
|
||||
ExtractTriangleFields fieldsWorklet(emptyField1,
|
||||
emptyField2,
|
||||
emptyField3,
|
||||
emptyField4,
|
||||
field1Range,
|
||||
field2Range,
|
||||
field3Range,
|
||||
field4Range);
|
||||
vtkm::worklet::DispatcherMapField<ExtractTriangleFields>(fieldsWorklet)
|
||||
.Invoke(tris,
|
||||
field1,
|
||||
field2,
|
||||
field3,
|
||||
field4,
|
||||
retval.Field1,
|
||||
retval.Field2,
|
||||
retval.Field3,
|
||||
retval.Field4);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static TriangleArrays UnpackTriangles(vtkm::cont::ArrayHandle<vtkm::Id4> tris,
|
||||
vtkm::cont::CoordinateSystem coords,
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f_32> normals)
|
||||
{
|
||||
TriangleArrays retval;
|
||||
|
||||
const auto numTris = tris.GetNumberOfValues();
|
||||
|
||||
bool extractNormals = normals.GetNumberOfValues() != 0;
|
||||
|
||||
retval.Vertices.Allocate(numTris * 3);
|
||||
if (extractNormals)
|
||||
retval.Normals.Allocate(numTris * 3);
|
||||
|
||||
ExtractTriangleVerticesAndNormals worklet(extractNormals);
|
||||
vtkm::worklet::DispatcherMapField<ExtractTriangleVerticesAndNormals>(worklet).Invoke(
|
||||
tris, coords, normals, retval.Vertices, retval.Normals);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// ANARIMapperTriangles definitions ///////////////////////////////////////////
|
||||
|
||||
ANARIMapperTriangles::ANARIMapperTriangles(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<ANARIMapperTriangles::ANARIHandles>();
|
||||
this->Handles->Device = device;
|
||||
auto& attributes = this->Handles->Parameters.Vertex.Attribute;
|
||||
std::fill(attributes.begin(), attributes.end(), nullptr);
|
||||
anari_cpp::retain(device, device);
|
||||
}
|
||||
|
||||
ANARIMapperTriangles::~ANARIMapperTriangles()
|
||||
{
|
||||
// ensure ANARI handles are released before host memory goes away
|
||||
this->Handles.reset();
|
||||
}
|
||||
|
||||
void ANARIMapperTriangles::SetActor(const ANARIActor& actor)
|
||||
{
|
||||
this->ANARIMapper::SetActor(actor);
|
||||
this->ConstructArrays(true);
|
||||
this->UpdateMaterial();
|
||||
}
|
||||
|
||||
void ANARIMapperTriangles::SetMapFieldAsAttribute(bool enabled)
|
||||
{
|
||||
this->ANARIMapper::SetMapFieldAsAttribute(enabled);
|
||||
this->UpdateGeometry();
|
||||
this->UpdateMaterial();
|
||||
}
|
||||
|
||||
void ANARIMapperTriangles::SetANARIColorMap(anari_cpp::Array1D color,
|
||||
anari_cpp::Array1D opacity,
|
||||
bool releaseArrays)
|
||||
{
|
||||
this->GetANARISurface();
|
||||
auto d = this->GetDevice();
|
||||
auto s = this->Handles->Sampler;
|
||||
anari_cpp::setParameter(d, s, "image", color);
|
||||
anari_cpp::commitParameters(d, s);
|
||||
this->ANARIMapper::SetANARIColorMap(color, opacity, releaseArrays);
|
||||
}
|
||||
|
||||
void ANARIMapperTriangles::SetANARIColorMapValueRange(const vtkm::Vec2f_32& valueRange)
|
||||
{
|
||||
this->GetANARISurface();
|
||||
auto s = this->Handles->Sampler;
|
||||
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);
|
||||
}
|
||||
|
||||
void ANARIMapperTriangles::SetCalculateNormals(bool enabled)
|
||||
{
|
||||
this->CalculateNormals = enabled;
|
||||
}
|
||||
|
||||
anari_cpp::Geometry ANARIMapperTriangles::GetANARIGeometry()
|
||||
{
|
||||
if (this->Handles->Geometry)
|
||||
return this->Handles->Geometry;
|
||||
|
||||
auto d = this->GetDevice();
|
||||
this->Handles->Geometry = anari_cpp::newObject<anari_cpp::Geometry>(d, "triangle");
|
||||
this->ConstructArrays();
|
||||
this->UpdateGeometry();
|
||||
return this->Handles->Geometry;
|
||||
}
|
||||
|
||||
anari_cpp::Surface ANARIMapperTriangles::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;
|
||||
}
|
||||
|
||||
bool ANARIMapperTriangles::NeedToGenerateData() const
|
||||
{
|
||||
const bool haveNormals = this->Handles->Parameters.Vertex.Normal != nullptr;
|
||||
const bool needNormals = this->CalculateNormals && !haveNormals;
|
||||
return !this->Current || needNormals;
|
||||
}
|
||||
|
||||
void ANARIMapperTriangles::ConstructArrays(bool regenerate)
|
||||
{
|
||||
if (regenerate)
|
||||
this->Current = false;
|
||||
|
||||
if (!regenerate && !this->NeedToGenerateData())
|
||||
return;
|
||||
|
||||
this->Current = true;
|
||||
this->Valid = false;
|
||||
|
||||
this->Handles->ReleaseArrays();
|
||||
|
||||
const auto& actor = this->GetActor();
|
||||
const auto& cells = actor.GetCellSet();
|
||||
|
||||
if (cells.GetNumberOfCells() == 0)
|
||||
{
|
||||
this->RefreshGroup();
|
||||
return;
|
||||
}
|
||||
|
||||
vtkm::rendering::raytracing::TriangleExtractor triExtractor;
|
||||
triExtractor.ExtractCells(cells);
|
||||
|
||||
if (triExtractor.GetNumberOfTriangles() == 0)
|
||||
{
|
||||
this->RefreshGroup();
|
||||
return;
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f_32> inNormals;
|
||||
|
||||
if (this->CalculateNormals)
|
||||
{
|
||||
vtkm::filter::vector_analysis::SurfaceNormals normalsFilter;
|
||||
normalsFilter.SetOutputFieldName("Normals");
|
||||
auto dataset = normalsFilter.Execute(actor.MakeDataSet());
|
||||
auto field = dataset.GetField("Normals");
|
||||
auto fieldArray = field.GetData();
|
||||
vtkm::cont::ArrayCopyShallowIfPossible(fieldArray, inNormals);
|
||||
}
|
||||
|
||||
auto tris = triExtractor.GetTriangles();
|
||||
|
||||
auto arrays = UnpackTriangles(tris, actor.GetCoordinateSystem(), inNormals);
|
||||
auto fieldArrays = UnpackFields(tris, actor.GetFieldSet(), this->GetColorTable().GetRange());
|
||||
|
||||
this->PrimaryField = actor.GetPrimaryFieldIndex();
|
||||
|
||||
auto numVerts = arrays.Vertices.GetNumberOfValues();
|
||||
|
||||
auto* v = (vtkm::Vec3f_32*)arrays.Vertices.GetBuffers()[0].ReadPointerHost(*arrays.Token);
|
||||
auto* n = (vtkm::Vec3f_32*)arrays.Normals.GetBuffers()[0].ReadPointerHost(*arrays.Token);
|
||||
|
||||
auto d = this->GetDevice();
|
||||
this->Handles->Parameters.NumPrimitives = numVerts / 3;
|
||||
this->Handles->Parameters.Vertex.Position =
|
||||
anari_cpp::newArray1D(d, v, NoopANARIDeleter, nullptr, numVerts);
|
||||
|
||||
if (fieldArrays.Field1.GetNumberOfValues() != 0)
|
||||
{
|
||||
auto* a = (float*)fieldArrays.Field1.GetBuffers()[0].ReadPointerHost(*fieldArrays.Token);
|
||||
this->Handles->Parameters.Vertex.Attribute[0] =
|
||||
anari_cpp::newArray1D(d, a, NoopANARIDeleter, nullptr, numVerts);
|
||||
}
|
||||
if (fieldArrays.Field2.GetNumberOfValues() != 0)
|
||||
{
|
||||
auto* a = (float*)fieldArrays.Field2.GetBuffers()[0].ReadPointerHost(*fieldArrays.Token);
|
||||
this->Handles->Parameters.Vertex.Attribute[1] =
|
||||
anari_cpp::newArray1D(d, a, NoopANARIDeleter, nullptr, numVerts);
|
||||
}
|
||||
if (fieldArrays.Field3.GetNumberOfValues() != 0)
|
||||
{
|
||||
auto* a = (float*)fieldArrays.Field3.GetBuffers()[0].ReadPointerHost(*fieldArrays.Token);
|
||||
this->Handles->Parameters.Vertex.Attribute[2] =
|
||||
anari_cpp::newArray1D(d, a, NoopANARIDeleter, nullptr, numVerts);
|
||||
}
|
||||
if (fieldArrays.Field4.GetNumberOfValues() != 0)
|
||||
{
|
||||
auto* a = (float*)fieldArrays.Field4.GetBuffers()[0].ReadPointerHost(*fieldArrays.Token);
|
||||
this->Handles->Parameters.Vertex.Attribute[3] =
|
||||
anari_cpp::newArray1D(d, a, NoopANARIDeleter, nullptr, numVerts);
|
||||
}
|
||||
if (this->CalculateNormals)
|
||||
{
|
||||
this->Handles->Parameters.Vertex.Normal =
|
||||
anari_cpp::newArray1D(d, n, NoopANARIDeleter, nullptr, arrays.Normals.GetNumberOfValues());
|
||||
}
|
||||
|
||||
// NOTE: usd device requires indices, but shouldn't
|
||||
{
|
||||
auto indexArray =
|
||||
anari_cpp::newArray1D(d, ANARI_UINT32_VEC3, this->Handles->Parameters.NumPrimitives);
|
||||
auto* begin = anari_cpp::map<unsigned int>(d, indexArray);
|
||||
auto* end = begin + numVerts;
|
||||
std::iota(begin, end, 0);
|
||||
anari_cpp::unmap(d, indexArray);
|
||||
this->Handles->Parameters.Primitive.Index = indexArray;
|
||||
}
|
||||
|
||||
this->UpdateGeometry();
|
||||
this->UpdateMaterial();
|
||||
|
||||
this->Arrays = arrays;
|
||||
this->FieldArrays = fieldArrays;
|
||||
this->Valid = true;
|
||||
|
||||
this->RefreshGroup();
|
||||
}
|
||||
|
||||
void ANARIMapperTriangles::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.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::unsetParameter(d, this->Handles->Geometry, "vertex.normal");
|
||||
anari_cpp::unsetParameter(d, this->Handles->Geometry, "primitive.index");
|
||||
|
||||
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);
|
||||
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]);
|
||||
}
|
||||
|
||||
if (CalculateNormals)
|
||||
{
|
||||
anari_cpp::setParameter(
|
||||
d, this->Handles->Geometry, "vertex.normal", this->Handles->Parameters.Vertex.Normal);
|
||||
}
|
||||
anari_cpp::setParameter(
|
||||
d, this->Handles->Geometry, "primitive.index", this->Handles->Parameters.Primitive.Index);
|
||||
}
|
||||
|
||||
anari_cpp::commitParameters(d, this->Handles->Geometry);
|
||||
}
|
||||
|
||||
void ANARIMapperTriangles::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);
|
||||
}
|
||||
|
||||
ANARIMapperTriangles::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 ANARIMapperTriangles::ANARIHandles::ReleaseArrays()
|
||||
{
|
||||
anari_cpp::release(this->Device, this->Parameters.Vertex.Position);
|
||||
anari_cpp::release(this->Device, this->Parameters.Vertex.Normal);
|
||||
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]);
|
||||
anari_cpp::release(this->Device, this->Parameters.Primitive.Index);
|
||||
this->Parameters.Vertex.Position = nullptr;
|
||||
this->Parameters.Vertex.Normal = 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;
|
||||
this->Parameters.Primitive.Index = nullptr;
|
||||
}
|
||||
|
||||
} // namespace anari
|
||||
} // namespace interop
|
||||
} // namespace vtkm
|
145
vtkm/interop/anari/ANARIMapperTriangles.h
Normal file
145
vtkm/interop/anari/ANARIMapperTriangles.h
Normal file
@ -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.
|
||||
//============================================================================
|
||||
|
||||
#ifndef vtk_m_interop_anari_ANARIMapperTriangles_h
|
||||
#define vtk_m_interop_anari_ANARIMapperTriangles_h
|
||||
|
||||
#include <vtkm/interop/anari/ANARIMapper.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace interop
|
||||
{
|
||||
namespace anari
|
||||
{
|
||||
|
||||
/// @brief Raw ANARI arrays and parameter values set on the `ANARIGeometry`.
|
||||
///
|
||||
struct TrianglesParameters
|
||||
{
|
||||
struct VertexData
|
||||
{
|
||||
anari_cpp::Array1D Position{ nullptr };
|
||||
anari_cpp::Array1D Normal{ nullptr };
|
||||
std::array<anari_cpp::Array1D, 4> Attribute;
|
||||
} Vertex{};
|
||||
|
||||
struct PrimitiveData
|
||||
{
|
||||
anari_cpp::Array1D Index{ nullptr };
|
||||
} Primitive{};
|
||||
|
||||
unsigned int NumPrimitives{ 0 };
|
||||
};
|
||||
|
||||
/// @brief VTK-m data arrays underlying the `ANARIArray` handles created by the mapper.
|
||||
///
|
||||
struct TriangleArrays
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f_32> Vertices;
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f_32> Normals;
|
||||
std::shared_ptr<vtkm::cont::Token> Token{ new vtkm::cont::Token };
|
||||
};
|
||||
|
||||
/// @brief VTK-m data arrays underlying the `ANARIArray` handles created by the mapper for field attributes.
|
||||
///
|
||||
struct TriangleFieldArrays
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32> Field1;
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32> Field2;
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32> Field3;
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32> Field4;
|
||||
std::shared_ptr<vtkm::cont::Token> Token{ new vtkm::cont::Token };
|
||||
};
|
||||
|
||||
/// @brief Mapper which triangulates cells into ANARI `triangle` geometry.
|
||||
///
|
||||
/// NOTE: This mapper will only color map values that are 1-component Float32
|
||||
/// fields, otherwise they will be ignored. This restriction will allow 2-4
|
||||
/// component fields in the future.
|
||||
struct VTKM_ANARI_EXPORT ANARIMapperTriangles : public ANARIMapper
|
||||
{
|
||||
/// @brief Constructor
|
||||
///
|
||||
ANARIMapperTriangles(
|
||||
anari_cpp::Device device,
|
||||
const ANARIActor& actor = {},
|
||||
const std::string& name = "<triangles>",
|
||||
const vtkm::cont::ColorTable& colorTable = vtkm::cont::ColorTable::Preset::Default);
|
||||
|
||||
/// @brief Destructor
|
||||
///
|
||||
~ANARIMapperTriangles() override;
|
||||
|
||||
/// @brief Set the current actor on this mapper.
|
||||
///
|
||||
/// See `ANARIMapper` for more detail.
|
||||
void SetActor(const ANARIActor& actor) override;
|
||||
|
||||
/// @brief Set whether fields from `ANARIActor` should end up as geometry attributes.
|
||||
///
|
||||
/// See `ANARIMapper` for more detail.
|
||||
void SetMapFieldAsAttribute(bool enabled) override;
|
||||
|
||||
/// @brief Set color map arrays using raw ANARI array handles.
|
||||
///
|
||||
/// See `ANARIMapper` for more detail.
|
||||
void SetANARIColorMap(anari_cpp::Array1D color,
|
||||
anari_cpp::Array1D opacity,
|
||||
bool releaseArrays = true) override;
|
||||
|
||||
/// @brief Set the value range (domain) for the color map.
|
||||
///
|
||||
void SetANARIColorMapValueRange(const vtkm::Vec2f_32& valueRange) override;
|
||||
|
||||
/// @brief Set whether `vertex.normal` data should also be calculated when triangulating geometry.
|
||||
///
|
||||
void SetCalculateNormals(bool enabled);
|
||||
|
||||
anari_cpp::Geometry GetANARIGeometry() override;
|
||||
anari_cpp::Surface GetANARISurface() override;
|
||||
|
||||
private:
|
||||
bool NeedToGenerateData() const;
|
||||
/// @brief Do the work to construct the basic ANARI arrays for the ANARIGeometry.
|
||||
/// @param regenerate Force the position/radius arrays are regenerated.
|
||||
///
|
||||
void ConstructArrays(bool regenerate = false);
|
||||
/// @brief Update ANARIGeometry object with the latest data from the actor.
|
||||
void UpdateGeometry();
|
||||
/// @brief Update ANARIMaterial object with the latest data from the actor.
|
||||
void UpdateMaterial();
|
||||
|
||||
/// @brief Container of all relevant ANARI scene object handles.
|
||||
struct ANARIHandles
|
||||
{
|
||||
anari_cpp::Device Device{ nullptr };
|
||||
anari_cpp::Geometry Geometry{ nullptr };
|
||||
anari_cpp::Sampler Sampler{ nullptr };
|
||||
anari_cpp::Material Material{ nullptr };
|
||||
anari_cpp::Surface Surface{ nullptr };
|
||||
TrianglesParameters Parameters;
|
||||
~ANARIHandles();
|
||||
void ReleaseArrays();
|
||||
};
|
||||
|
||||
std::shared_ptr<ANARIHandles> Handles;
|
||||
|
||||
bool CalculateNormals{ false };
|
||||
vtkm::IdComponent PrimaryField{ 0 };
|
||||
TriangleArrays Arrays;
|
||||
TriangleFieldArrays FieldArrays;
|
||||
};
|
||||
|
||||
} // namespace anari
|
||||
} // namespace interop
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
211
vtkm/interop/anari/ANARIMapperVolume.cxx
Normal file
211
vtkm/interop/anari/ANARIMapperVolume.cxx
Normal file
@ -0,0 +1,211 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/interop/anari/ANARIMapperVolume.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace interop
|
||||
{
|
||||
namespace anari
|
||||
{
|
||||
|
||||
ANARIMapperVolume::ANARIMapperVolume(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<ANARIMapperVolume::ANARIHandles>();
|
||||
this->Handles->Device = device;
|
||||
anari_cpp::retain(device, device);
|
||||
}
|
||||
|
||||
ANARIMapperVolume::~ANARIMapperVolume()
|
||||
{
|
||||
// ensure ANARI handles are released before host memory goes away
|
||||
this->Handles.reset();
|
||||
}
|
||||
|
||||
void ANARIMapperVolume::SetActor(const ANARIActor& actor)
|
||||
{
|
||||
this->ANARIMapper::SetActor(actor);
|
||||
this->ConstructArrays(true);
|
||||
}
|
||||
|
||||
void ANARIMapperVolume::SetANARIColorMap(anari_cpp::Array1D color,
|
||||
anari_cpp::Array1D opacity,
|
||||
bool releaseArrays)
|
||||
{
|
||||
auto d = this->GetDevice();
|
||||
auto v = this->GetANARIVolume();
|
||||
anari_cpp::setParameter(d, v, "color", color);
|
||||
anari_cpp::setParameter(d, v, "opacity", opacity);
|
||||
anari_cpp::commitParameters(d, v);
|
||||
this->ANARIMapper::SetANARIColorMap(color, opacity, releaseArrays);
|
||||
}
|
||||
|
||||
void ANARIMapperVolume::SetANARIColorMapValueRange(const vtkm::Vec2f_32& valueRange)
|
||||
{
|
||||
auto d = this->GetDevice();
|
||||
auto v = this->GetANARIVolume();
|
||||
anari_cpp::setParameter(d, v, "valueRange", ANARI_FLOAT32_BOX1, &valueRange);
|
||||
anari_cpp::commitParameters(d, v);
|
||||
}
|
||||
|
||||
void ANARIMapperVolume::SetANARIColorMapOpacityScale(vtkm::Float32 opacityScale)
|
||||
{
|
||||
auto d = this->GetDevice();
|
||||
auto v = this->GetANARIVolume();
|
||||
anari_cpp::setParameter(d, v, "densityScale", opacityScale);
|
||||
anari_cpp::commitParameters(d, v);
|
||||
}
|
||||
|
||||
anari_cpp::SpatialField ANARIMapperVolume::GetANARISpatialField()
|
||||
{
|
||||
if (this->Handles->SpatialField)
|
||||
return this->Handles->SpatialField;
|
||||
|
||||
this->Handles->SpatialField =
|
||||
anari_cpp::newObject<anari_cpp::SpatialField>(this->GetDevice(), "structuredRegular");
|
||||
this->ConstructArrays();
|
||||
this->UpdateSpatialField();
|
||||
return this->Handles->SpatialField;
|
||||
}
|
||||
|
||||
anari_cpp::Volume ANARIMapperVolume::GetANARIVolume()
|
||||
{
|
||||
if (this->Handles->Volume)
|
||||
return this->Handles->Volume;
|
||||
|
||||
auto d = this->GetDevice();
|
||||
|
||||
this->Handles->Volume = anari_cpp::newObject<anari_cpp::Volume>(d, "transferFunction1D");
|
||||
|
||||
auto colorArray = anari_cpp::newArray1D(d, ANARI_FLOAT32_VEC3, 3);
|
||||
auto* colors = anari_cpp::map<vtkm::Vec3f_32>(d, colorArray);
|
||||
colors[0] = vtkm::Vec3f_32(1.f, 0.f, 0.f);
|
||||
colors[1] = vtkm::Vec3f_32(0.f, 1.f, 0.f);
|
||||
colors[2] = vtkm::Vec3f_32(0.f, 0.f, 1.f);
|
||||
anari_cpp::unmap(d, colorArray);
|
||||
|
||||
auto opacityArray = anari_cpp::newArray1D(d, ANARI_FLOAT32, 2);
|
||||
auto* opacities = anari_cpp::map<float>(d, opacityArray);
|
||||
opacities[0] = 0.f;
|
||||
opacities[1] = 1.f;
|
||||
anari_cpp::unmap(d, opacityArray);
|
||||
|
||||
anari_cpp::setAndReleaseParameter(d, this->Handles->Volume, "color", colorArray);
|
||||
anari_cpp::setAndReleaseParameter(d, this->Handles->Volume, "opacity", opacityArray);
|
||||
anari_cpp::setParameter(d, this->Handles->Volume, "field", this->GetANARISpatialField());
|
||||
anari_cpp::setParameter(d, this->Handles->Volume, "name", this->MakeObjectName("volume"));
|
||||
anari_cpp::commitParameters(d, this->Handles->Volume);
|
||||
|
||||
SetANARIColorMapValueRange(vtkm::Vec2f_32(0.f, 10.f));
|
||||
|
||||
return this->Handles->Volume;
|
||||
}
|
||||
|
||||
void ANARIMapperVolume::ConstructArrays(bool regenerate)
|
||||
{
|
||||
if (regenerate)
|
||||
this->Current = false;
|
||||
|
||||
if (this->Current)
|
||||
return;
|
||||
|
||||
this->Current = true;
|
||||
this->Valid = false;
|
||||
|
||||
const auto& actor = this->GetActor();
|
||||
const auto& coords = actor.GetCoordinateSystem();
|
||||
const auto& cells = actor.GetCellSet();
|
||||
const auto& fieldArray = actor.GetField().GetData();
|
||||
|
||||
const bool isStructured = cells.IsType<vtkm::cont::CellSetStructured<3>>();
|
||||
const bool isFloat = fieldArray.IsType<vtkm::cont::ArrayHandle<vtkm::Float32>>();
|
||||
|
||||
this->Handles->ReleaseArrays();
|
||||
|
||||
if (isStructured && isFloat)
|
||||
{
|
||||
auto structuredCells = cells.AsCellSet<vtkm::cont::CellSetStructured<3>>();
|
||||
auto pdims = structuredCells.GetPointDimensions();
|
||||
|
||||
VolumeArrays arrays;
|
||||
|
||||
auto d = this->GetDevice();
|
||||
|
||||
arrays.Data = fieldArray.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Float32>>();
|
||||
|
||||
auto* ptr = (float*)arrays.Data.GetBuffers()[0].ReadPointerHost(*arrays.Token);
|
||||
|
||||
auto bounds = coords.GetBounds();
|
||||
vtkm::Vec3f_32 bLower(bounds.X.Min, bounds.Y.Min, bounds.Z.Min);
|
||||
vtkm::Vec3f_32 bUpper(bounds.X.Max, bounds.Y.Max, bounds.Z.Max);
|
||||
vtkm::Vec3f_32 size = bUpper - bLower;
|
||||
|
||||
vtkm::Vec3ui_32 dims(pdims[0], pdims[1], pdims[2]);
|
||||
auto spacing = size / (vtkm::Vec3f_32(dims) - 1.f);
|
||||
|
||||
std::memcpy(this->Handles->Parameters.Dims, &dims, sizeof(dims));
|
||||
std::memcpy(this->Handles->Parameters.Origin, &bLower, sizeof(bLower));
|
||||
std::memcpy(this->Handles->Parameters.Spacing, &spacing, sizeof(spacing));
|
||||
this->Handles->Parameters.Data =
|
||||
anari_cpp::newArray3D(d, ptr, NoopANARIDeleter, nullptr, dims[0], dims[1], dims[2]);
|
||||
|
||||
this->Arrays = arrays;
|
||||
this->Valid = true;
|
||||
}
|
||||
|
||||
this->UpdateSpatialField();
|
||||
this->RefreshGroup();
|
||||
}
|
||||
|
||||
void ANARIMapperVolume::UpdateSpatialField()
|
||||
{
|
||||
auto d = this->GetDevice();
|
||||
|
||||
anari_cpp::unsetParameter(d, this->Handles->SpatialField, "origin");
|
||||
anari_cpp::unsetParameter(d, this->Handles->SpatialField, "spacing");
|
||||
anari_cpp::unsetParameter(d, this->Handles->SpatialField, "data");
|
||||
|
||||
anari_cpp::setParameter(
|
||||
d, this->Handles->SpatialField, "name", this->MakeObjectName("spatialField"));
|
||||
|
||||
if (this->Handles->Parameters.Data)
|
||||
{
|
||||
anari_cpp::setParameter(
|
||||
d, this->Handles->SpatialField, "origin", this->Handles->Parameters.Origin);
|
||||
anari_cpp::setParameter(
|
||||
d, this->Handles->SpatialField, "spacing", this->Handles->Parameters.Spacing);
|
||||
anari_cpp::setParameter(d, this->Handles->SpatialField, "data", this->Handles->Parameters.Data);
|
||||
}
|
||||
|
||||
anari_cpp::commitParameters(d, this->Handles->SpatialField);
|
||||
}
|
||||
|
||||
ANARIMapperVolume::ANARIHandles::~ANARIHandles()
|
||||
{
|
||||
this->ReleaseArrays();
|
||||
anari_cpp::release(this->Device, this->Volume);
|
||||
anari_cpp::release(this->Device, this->SpatialField);
|
||||
anari_cpp::release(this->Device, this->Device);
|
||||
}
|
||||
|
||||
void ANARIMapperVolume::ANARIHandles::ReleaseArrays()
|
||||
{
|
||||
anari_cpp::release(this->Device, this->Parameters.Data);
|
||||
this->Parameters.Data = nullptr;
|
||||
}
|
||||
|
||||
} // namespace anari
|
||||
} // namespace interop
|
||||
} // namespace vtkm
|
108
vtkm/interop/anari/ANARIMapperVolume.h
Normal file
108
vtkm/interop/anari/ANARIMapperVolume.h
Normal file
@ -0,0 +1,108 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#ifndef vtk_m_interop_anari_ANARIMapperVolume_h
|
||||
#define vtk_m_interop_anari_ANARIMapperVolume_h
|
||||
|
||||
#include <vtkm/interop/anari/ANARIMapper.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace interop
|
||||
{
|
||||
namespace anari
|
||||
{
|
||||
|
||||
/// @brief Raw ANARI arrays and parameter values set on the `ANARISpatialField`.
|
||||
///
|
||||
struct VolumeParameters
|
||||
{
|
||||
anari_cpp::Array3D Data{ nullptr };
|
||||
int Dims[3];
|
||||
float Origin[3];
|
||||
float Spacing[3];
|
||||
};
|
||||
|
||||
/// @brief VTK-m data arrays underlying the `ANARIArray` handles created by the mapper.
|
||||
///
|
||||
struct VolumeArrays
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32> Data;
|
||||
std::shared_ptr<vtkm::cont::Token> Token{ new vtkm::cont::Token };
|
||||
};
|
||||
|
||||
/// @brief Mapper which turns structured volumes into a single ANARI `transferFunction1D` volume.
|
||||
///
|
||||
/// NOTE: This currently only supports Float32 scalar fields. In the future this
|
||||
/// mapper will also support Uint8, Uint16, and Float64 scalar fields.
|
||||
struct VTKM_ANARI_EXPORT ANARIMapperVolume : public ANARIMapper
|
||||
{
|
||||
/// @brief Constructor
|
||||
///
|
||||
ANARIMapperVolume(
|
||||
anari_cpp::Device device,
|
||||
const ANARIActor& actor = {},
|
||||
const std::string& name = "<volume>",
|
||||
const vtkm::cont::ColorTable& colorTable = vtkm::cont::ColorTable::Preset::Default);
|
||||
|
||||
/// @brief Destructor
|
||||
///
|
||||
~ANARIMapperVolume() override;
|
||||
|
||||
/// @brief Set the current actor on this mapper.
|
||||
///
|
||||
/// See `ANARIMapper` for more detail.
|
||||
void SetActor(const ANARIActor& actor) override;
|
||||
|
||||
/// @brief Set color map arrays using raw ANARI array handles.
|
||||
///
|
||||
/// See `ANARIMapper` for more detail.
|
||||
void SetANARIColorMap(anari_cpp::Array1D color,
|
||||
anari_cpp::Array1D opacity,
|
||||
bool releaseArrays = true) override;
|
||||
/// @brief Set the value range (domain) for the color map.
|
||||
///
|
||||
void SetANARIColorMapValueRange(const vtkm::Vec2f_32& valueRange) override;
|
||||
|
||||
/// @brief Set a scale factor for opacity.
|
||||
///
|
||||
void SetANARIColorMapOpacityScale(vtkm::Float32 opacityScale) override;
|
||||
|
||||
anari_cpp::SpatialField GetANARISpatialField() override;
|
||||
anari_cpp::Volume GetANARIVolume() override;
|
||||
|
||||
private:
|
||||
/// @brief Do the work to construct the basic ANARI arrays for the ANARIGeometry.
|
||||
/// @param regenerate Force the position/radius arrays are regenerated.
|
||||
///
|
||||
void ConstructArrays(bool regenerate = false);
|
||||
/// @brief Update ANARISpatialField object with the latest data from the actor.
|
||||
void UpdateSpatialField();
|
||||
|
||||
/// @brief Container of all relevant ANARI scene object handles.
|
||||
struct ANARIHandles
|
||||
{
|
||||
anari_cpp::Device Device{ nullptr };
|
||||
anari_cpp::SpatialField SpatialField{ nullptr };
|
||||
anari_cpp::Volume Volume{ nullptr };
|
||||
VolumeParameters Parameters;
|
||||
~ANARIHandles();
|
||||
void ReleaseArrays();
|
||||
};
|
||||
|
||||
std::shared_ptr<ANARIHandles> Handles;
|
||||
VolumeArrays Arrays;
|
||||
};
|
||||
|
||||
} // namespace anari
|
||||
} // namespace interop
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
155
vtkm/interop/anari/ANARIScene.cxx
Normal file
155
vtkm/interop/anari/ANARIScene.cxx
Normal file
@ -0,0 +1,155 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/interop/anari/ANARIScene.h>
|
||||
// std
|
||||
#include <algorithm>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace interop
|
||||
{
|
||||
namespace anari
|
||||
{
|
||||
|
||||
ANARIScene::ANARIScene(anari_cpp::Device device)
|
||||
: Device(device)
|
||||
{
|
||||
anari_cpp::retain(this->Device, this->Device);
|
||||
}
|
||||
|
||||
ANARIScene::~ANARIScene()
|
||||
{
|
||||
anari_cpp::release(this->Device, this->World);
|
||||
anari_cpp::release(this->Device, this->Device);
|
||||
}
|
||||
|
||||
vtkm::IdComponent ANARIScene::GetNumberOfMappers() const
|
||||
{
|
||||
return static_cast<vtkm::IdComponent>(this->Mappers.size());
|
||||
}
|
||||
|
||||
bool ANARIScene::HasMapperWithName(const char* _name) const
|
||||
{
|
||||
std::string name = _name;
|
||||
auto itr = std::find_if(this->Mappers.begin(), this->Mappers.end(), [&](auto& m) {
|
||||
return m.Mapper->GetName() == name;
|
||||
});
|
||||
return itr != this->Mappers.end();
|
||||
}
|
||||
|
||||
vtkm::IdComponent ANARIScene::GetMapperIndexByName(const char* _name)
|
||||
{
|
||||
std::string name = _name;
|
||||
auto itr = std::find_if(this->Mappers.begin(), this->Mappers.end(), [&](auto& m) {
|
||||
return m.Mapper->GetName() == name;
|
||||
});
|
||||
return static_cast<vtkm::IdComponent>(std::distance(this->Mappers.begin(), itr));
|
||||
}
|
||||
|
||||
ANARIMapper& ANARIScene::GetMapper(vtkm::IdComponent id)
|
||||
{
|
||||
return *this->Mappers[id].Mapper;
|
||||
}
|
||||
|
||||
ANARIMapper& ANARIScene::GetMapper(const char* _name)
|
||||
{
|
||||
std::string name = _name;
|
||||
auto itr = std::find_if(this->Mappers.begin(), this->Mappers.end(), [&](auto& m) {
|
||||
return m.Mapper->GetName() == name;
|
||||
});
|
||||
return *itr->Mapper;
|
||||
}
|
||||
|
||||
bool ANARIScene::GetMapperVisible(vtkm::IdComponent id) const
|
||||
{
|
||||
return this->Mappers[id].Show;
|
||||
}
|
||||
|
||||
void ANARIScene::SetMapperVisible(vtkm::IdComponent id, bool shown)
|
||||
{
|
||||
auto& m = this->Mappers[id];
|
||||
if (m.Show != shown)
|
||||
{
|
||||
m.Show = shown;
|
||||
this->UpdateWorld();
|
||||
}
|
||||
}
|
||||
|
||||
void ANARIScene::RemoveMapper(vtkm::IdComponent id)
|
||||
{
|
||||
this->Mappers.erase(this->Mappers.begin() + id);
|
||||
this->UpdateWorld();
|
||||
}
|
||||
|
||||
void ANARIScene::RemoveMapper(const char* name)
|
||||
{
|
||||
std::string n = name;
|
||||
this->Mappers.erase(std::remove_if(this->Mappers.begin(),
|
||||
this->Mappers.end(),
|
||||
[&](auto& m) { return m.Mapper->GetName() == n; }),
|
||||
this->Mappers.end());
|
||||
this->UpdateWorld();
|
||||
}
|
||||
|
||||
void ANARIScene::RemoveAllMappers()
|
||||
{
|
||||
this->Mappers.clear();
|
||||
this->UpdateWorld();
|
||||
}
|
||||
|
||||
anari_cpp::Device ANARIScene::GetDevice() const
|
||||
{
|
||||
return this->Device;
|
||||
}
|
||||
|
||||
anari_cpp::World ANARIScene::GetANARIWorld()
|
||||
{
|
||||
if (!this->World)
|
||||
{
|
||||
auto d = this->GetDevice();
|
||||
this->World = anari_cpp::newObject<anari_cpp::World>(d);
|
||||
anari_cpp::setParameter(d, this->World, "name", "scene");
|
||||
this->UpdateWorld();
|
||||
}
|
||||
|
||||
return this->World;
|
||||
}
|
||||
|
||||
void ANARIScene::UpdateWorld()
|
||||
{
|
||||
if (!this->World)
|
||||
return; // nobody has asked for the world yet, so don't actually do anything
|
||||
|
||||
auto d = this->GetDevice();
|
||||
|
||||
std::vector<anari_cpp::Instance> instances;
|
||||
|
||||
for (auto& m : this->Mappers)
|
||||
{
|
||||
auto i = m.Mapper->GetANARIInstance();
|
||||
if (i && m.Show)
|
||||
instances.push_back(i);
|
||||
}
|
||||
|
||||
if (!instances.empty())
|
||||
{
|
||||
anari_cpp::setAndReleaseParameter(
|
||||
d, this->World, "instance", anari_cpp::newArray1D(d, instances.data(), instances.size()));
|
||||
}
|
||||
else
|
||||
anari_cpp::unsetParameter(d, this->World, "instance");
|
||||
|
||||
anari_cpp::commitParameters(d, this->World);
|
||||
}
|
||||
|
||||
} // namespace anari
|
||||
} // namespace interop
|
||||
} // namespace vtkm
|
176
vtkm/interop/anari/ANARIScene.h
Normal file
176
vtkm/interop/anari/ANARIScene.h
Normal file
@ -0,0 +1,176 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#ifndef vtk_m_interop_anari_ANARIScene_h
|
||||
#define vtk_m_interop_anari_ANARIScene_h
|
||||
|
||||
#include <vtkm/interop/anari/ANARIMapper.h>
|
||||
// std
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace interop
|
||||
{
|
||||
namespace anari
|
||||
{
|
||||
|
||||
/// @brief Object which manages a collection of mappers representing a single scene.
|
||||
///
|
||||
/// This object is a container of named mappers which will automatically keep
|
||||
/// an `ANARIWorld` up to date which contains any `ANARISurface` or
|
||||
/// `ANARIVolume` objects coming from the contained mappers. While applications
|
||||
/// are free to do this work themselves, it is very convenient and useful to
|
||||
/// let `ANARIScene` do the work of keeping an `ANARIWorld` up to date for you.
|
||||
///
|
||||
/// Mappers in `ANARIScene` can also be selectively hidden for quick scene
|
||||
/// updates. A hidden mapper's geometry/volume are just skipped when updating
|
||||
/// the list of object handles in the world.
|
||||
///
|
||||
/// NOTE: This object will not create any lights in the scene, so the
|
||||
/// `ANARIWorld` used by the application is expected to have application-managed
|
||||
/// `ANARILight` objects added to it when desired.
|
||||
///
|
||||
/// NOTE: Unlike `ANARIMapper` and `ANARIActor`, `ANARIScene` is not C++
|
||||
/// copyable or movable.
|
||||
struct VTKM_ANARI_EXPORT ANARIScene
|
||||
{
|
||||
/// @brief Constructor
|
||||
///
|
||||
ANARIScene(anari_cpp::Device device);
|
||||
|
||||
/// @brief Destructor
|
||||
///
|
||||
~ANARIScene();
|
||||
|
||||
ANARIScene(const ANARIScene&) = delete;
|
||||
ANARIScene(ANARIScene&&) = delete;
|
||||
ANARIScene& operator=(const ANARIScene&) = delete;
|
||||
ANARIScene& operator=(ANARIScene&&) = delete;
|
||||
|
||||
/// @brief Add a mapper to the scene.
|
||||
/// @tparam ANARIMapperType Any subclass of `ANARIMapper`.
|
||||
///
|
||||
/// NOTE: This will replace any mapper that has the same name.
|
||||
template <typename ANARIMapperType>
|
||||
ANARIMapperType& AddMapper(const ANARIMapperType& mapper, bool visible = true);
|
||||
|
||||
/// @brief Add a mapper to the scene.
|
||||
/// @tparam ANARIMapperType Any subclass of `ANARIMapper`.
|
||||
///
|
||||
/// NOTE: Replace the i'th mapper with a new instance.
|
||||
/// NOTE: It is undefined behavior to use this to put 2 or more mappers in the
|
||||
/// scene with the same name.
|
||||
template <typename ANARIMapperType>
|
||||
void ReplaceMapper(const ANARIMapperType& newMapper, vtkm::IdComponent id, bool visible);
|
||||
|
||||
/// @brief Get number of mappers in this scene.
|
||||
///
|
||||
vtkm::IdComponent GetNumberOfMappers() const;
|
||||
|
||||
/// @brief Ask whether a mapper has the passed in name or not.
|
||||
///
|
||||
bool HasMapperWithName(const char* name) const;
|
||||
|
||||
/// @brief Get the index to the mapper with the given name.
|
||||
///
|
||||
vtkm::IdComponent GetMapperIndexByName(const char* name);
|
||||
|
||||
/// @brief Get the associated mapper by index.
|
||||
///
|
||||
ANARIMapper& GetMapper(vtkm::IdComponent id);
|
||||
|
||||
/// @brief Get the associated mapper by name.
|
||||
///
|
||||
ANARIMapper& GetMapper(const char* name);
|
||||
|
||||
/// @brief Get the associated mapper by name.
|
||||
///
|
||||
bool GetMapperVisible(vtkm::IdComponent id) const;
|
||||
void SetMapperVisible(vtkm::IdComponent id, bool shown);
|
||||
|
||||
/// @brief Remove mapper by index.
|
||||
///
|
||||
void RemoveMapper(vtkm::IdComponent id);
|
||||
|
||||
/// @brief Remove mapper by name.
|
||||
///
|
||||
void RemoveMapper(const char* name);
|
||||
|
||||
/// @brief Clear out this scene of all mappers.
|
||||
void RemoveAllMappers();
|
||||
|
||||
/// @brief Get the `ANARIDevice` handle this scene is talking to.
|
||||
///
|
||||
/// NOTE: This handle is not retained, so applications should not release it.
|
||||
anari_cpp::Device GetDevice() const;
|
||||
|
||||
/// @brief Get the `ANARIWorld` handle this scene is working on.
|
||||
///
|
||||
/// NOTE: This handle is not retained, so applications should not release it.
|
||||
anari_cpp::World GetANARIWorld();
|
||||
|
||||
private:
|
||||
void UpdateWorld();
|
||||
|
||||
anari_cpp::Device Device{ nullptr };
|
||||
anari_cpp::World World{ nullptr };
|
||||
|
||||
struct SceneMapper
|
||||
{
|
||||
std::unique_ptr<ANARIMapper> Mapper;
|
||||
bool Show{ true };
|
||||
};
|
||||
|
||||
std::vector<SceneMapper> Mappers;
|
||||
};
|
||||
|
||||
// Inlined definitions ////////////////////////////////////////////////////////
|
||||
|
||||
template <typename ANARIMapperType>
|
||||
inline ANARIMapperType& ANARIScene::AddMapper(const ANARIMapperType& mapper, bool visible)
|
||||
{
|
||||
static_assert(std::is_base_of<ANARIMapper, ANARIMapperType>::value,
|
||||
"Only ANARIMapper types can be added to ANARIScene");
|
||||
|
||||
auto* name = mapper.GetName();
|
||||
if (HasMapperWithName(name))
|
||||
{
|
||||
auto idx = GetMapperIndexByName(name);
|
||||
ReplaceMapper(mapper, idx, visible);
|
||||
return (ANARIMapperType&)GetMapper(idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->Mappers.push_back({ std::make_unique<ANARIMapperType>(mapper), visible });
|
||||
UpdateWorld();
|
||||
return (ANARIMapperType&)GetMapper(GetNumberOfMappers() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ANARIMapperType>
|
||||
inline void ANARIScene::ReplaceMapper(const ANARIMapperType& newMapper,
|
||||
vtkm::IdComponent id,
|
||||
bool visible)
|
||||
{
|
||||
static_assert(std::is_base_of<ANARIMapper, ANARIMapperType>::value,
|
||||
"Only ANARIMapper types can be added to ANARIScene");
|
||||
const bool wasVisible = GetMapperVisible(id);
|
||||
Mappers[id] = { std::make_unique<ANARIMapperType>(newMapper), visible };
|
||||
if (wasVisible || visible)
|
||||
UpdateWorld();
|
||||
}
|
||||
|
||||
} // namespace anari
|
||||
} // namespace interop
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
47
vtkm/interop/anari/CMakeLists.txt
Normal file
47
vtkm/interop/anari/CMakeLists.txt
Normal file
@ -0,0 +1,47 @@
|
||||
##============================================================================
|
||||
## 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.
|
||||
##============================================================================
|
||||
|
||||
find_package(anari 0.7.0 REQUIRED)
|
||||
|
||||
set(headers
|
||||
ANARIActor.h
|
||||
ANARIMapper.h
|
||||
ANARIMapperGlyphs.h
|
||||
ANARIMapperPoints.h
|
||||
ANARIMapperTriangles.h
|
||||
ANARIMapperVolume.h
|
||||
ANARIScene.h
|
||||
VtkmANARITypes.h
|
||||
)
|
||||
|
||||
set(sources
|
||||
ANARIActor.cxx
|
||||
ANARIMapper.cxx
|
||||
ANARIScene.cxx
|
||||
VtkmANARITypes.cxx
|
||||
)
|
||||
|
||||
set(device_sources
|
||||
ANARIMapperGlyphs.cxx
|
||||
ANARIMapperPoints.cxx
|
||||
ANARIMapperTriangles.cxx
|
||||
ANARIMapperVolume.cxx
|
||||
../../rendering/raytracing/SphereExtractor.cxx
|
||||
)
|
||||
|
||||
|
||||
vtkm_library(
|
||||
NAME vtkm_anari
|
||||
SOURCES ${sources}
|
||||
HEADERS ${headers}
|
||||
DEVICE_SOURCES ${device_sources}
|
||||
)
|
||||
|
||||
target_link_libraries(vtkm_anari PUBLIC anari::anari)
|
26
vtkm/interop/anari/VtkmANARITypes.cxx
Normal file
26
vtkm/interop/anari/VtkmANARITypes.cxx
Normal file
@ -0,0 +1,26 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#include "VtkmANARITypes.h"
|
||||
|
||||
namespace anari
|
||||
{
|
||||
|
||||
ANARI_TYPEFOR_DEFINITION(vtkm::Vec2f_32);
|
||||
ANARI_TYPEFOR_DEFINITION(vtkm::Vec3f_32);
|
||||
ANARI_TYPEFOR_DEFINITION(vtkm::Vec4f_32);
|
||||
ANARI_TYPEFOR_DEFINITION(vtkm::Vec2i_32);
|
||||
ANARI_TYPEFOR_DEFINITION(vtkm::Vec3i_32);
|
||||
ANARI_TYPEFOR_DEFINITION(vtkm::Vec4i_32);
|
||||
ANARI_TYPEFOR_DEFINITION(vtkm::Vec2ui_32);
|
||||
ANARI_TYPEFOR_DEFINITION(vtkm::Vec3ui_32);
|
||||
ANARI_TYPEFOR_DEFINITION(vtkm::Vec4ui_32);
|
||||
|
||||
} // namespace anari
|
43
vtkm/interop/anari/VtkmANARITypes.h
Normal file
43
vtkm/interop/anari/VtkmANARITypes.h
Normal file
@ -0,0 +1,43 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#ifndef vtk_m_interop_anari_VtkmANARITypes_h
|
||||
#define vtk_m_interop_anari_VtkmANARITypes_h
|
||||
|
||||
// vtk-m
|
||||
#include <vtkm/Types.h>
|
||||
// anari
|
||||
#include <anari/anari_cpp.hpp>
|
||||
#if ANARI_SDK_VERSION_MINOR <= 3
|
||||
#include <anari/type_utility.h>
|
||||
#endif
|
||||
|
||||
namespace anari_cpp = ::anari;
|
||||
|
||||
namespace anari
|
||||
{
|
||||
|
||||
/// These declarations let ANARI C++ bindings infer the correct `ANARIDataType`
|
||||
/// enum value from VTK-m's C++ math types. This header should be included
|
||||
/// before any code which needs this type inference to function.
|
||||
|
||||
ANARI_TYPEFOR_SPECIALIZATION(vtkm::Vec2f_32, ANARI_FLOAT32_VEC2);
|
||||
ANARI_TYPEFOR_SPECIALIZATION(vtkm::Vec3f_32, ANARI_FLOAT32_VEC3);
|
||||
ANARI_TYPEFOR_SPECIALIZATION(vtkm::Vec4f_32, ANARI_FLOAT32_VEC4);
|
||||
ANARI_TYPEFOR_SPECIALIZATION(vtkm::Vec2i_32, ANARI_INT32_VEC2);
|
||||
ANARI_TYPEFOR_SPECIALIZATION(vtkm::Vec3i_32, ANARI_INT32_VEC3);
|
||||
ANARI_TYPEFOR_SPECIALIZATION(vtkm::Vec4i_32, ANARI_INT32_VEC4);
|
||||
ANARI_TYPEFOR_SPECIALIZATION(vtkm::Vec2ui_32, ANARI_UINT32_VEC2);
|
||||
ANARI_TYPEFOR_SPECIALIZATION(vtkm::Vec3ui_32, ANARI_UINT32_VEC3);
|
||||
ANARI_TYPEFOR_SPECIALIZATION(vtkm::Vec4ui_32, ANARI_UINT32_VEC4);
|
||||
|
||||
} // namespace anari
|
||||
|
||||
#endif
|
149
vtkm/interop/anari/testing/ANARITestCommon.h
Normal file
149
vtkm/interop/anari/testing/ANARITestCommon.h
Normal file
@ -0,0 +1,149 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#ifndef vtk_m_interop_anari_testing_ANARITestCommon_h
|
||||
#define vtk_m_interop_anari_testing_ANARITestCommon_h
|
||||
|
||||
// vtk-m
|
||||
#include <vtkm/cont/DataSetBuilderUniform.h>
|
||||
#include <vtkm/interop/anari/ANARIMapper.h>
|
||||
#include <vtkm/rendering/testing/Testing.h>
|
||||
#include <vtkm/testing/Testing.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
static void StatusFunc(const void* userData,
|
||||
ANARIDevice /*device*/,
|
||||
ANARIObject source,
|
||||
ANARIDataType /*sourceType*/,
|
||||
ANARIStatusSeverity severity,
|
||||
ANARIStatusCode /*code*/,
|
||||
const char* message)
|
||||
{
|
||||
bool verbose = *(bool*)userData;
|
||||
if (!verbose)
|
||||
return;
|
||||
|
||||
if (severity == ANARI_SEVERITY_FATAL_ERROR)
|
||||
{
|
||||
fprintf(stderr, "[FATAL][%p] %s\n", source, message);
|
||||
}
|
||||
else if (severity == ANARI_SEVERITY_ERROR)
|
||||
{
|
||||
fprintf(stderr, "[ERROR][%p] %s\n", source, message);
|
||||
}
|
||||
else if (severity == ANARI_SEVERITY_WARNING)
|
||||
{
|
||||
fprintf(stderr, "[WARN ][%p] %s\n", source, message);
|
||||
}
|
||||
else if (severity == ANARI_SEVERITY_PERFORMANCE_WARNING)
|
||||
{
|
||||
fprintf(stderr, "[PERF ][%p] %s\n", source, message);
|
||||
}
|
||||
else if (severity == ANARI_SEVERITY_INFO)
|
||||
{
|
||||
fprintf(stderr, "[INFO ][%p] %s\n", source, message);
|
||||
}
|
||||
else if (severity == ANARI_SEVERITY_DEBUG)
|
||||
{
|
||||
fprintf(stderr, "[DEBUG][%p] %s\n", source, message);
|
||||
}
|
||||
}
|
||||
|
||||
static void setColorMap(anari_cpp::Device d, vtkm::interop::anari::ANARIMapper& mapper)
|
||||
{
|
||||
auto colorArray = anari_cpp::newArray1D(d, ANARI_FLOAT32_VEC3, 3);
|
||||
auto* colors = anari_cpp::map<vtkm::Vec3f_32>(d, colorArray);
|
||||
colors[0] = vtkm::Vec3f_32(0.f, 0.f, 1.f);
|
||||
colors[1] = vtkm::Vec3f_32(0.f, 1.f, 0.f);
|
||||
colors[2] = vtkm::Vec3f_32(1.f, 0.f, 0.f);
|
||||
anari_cpp::unmap(d, colorArray);
|
||||
|
||||
auto opacityArray = anari_cpp::newArray1D(d, ANARI_FLOAT32, 2);
|
||||
auto* opacities = anari_cpp::map<float>(d, opacityArray);
|
||||
opacities[0] = 0.f;
|
||||
opacities[1] = 1.f;
|
||||
anari_cpp::unmap(d, opacityArray);
|
||||
|
||||
mapper.SetANARIColorMap(colorArray, opacityArray, true);
|
||||
mapper.SetANARIColorMapValueRange(vtkm::Vec2f_32(0.f, 10.f));
|
||||
mapper.SetANARIColorMapOpacityScale(0.5f);
|
||||
}
|
||||
|
||||
static anari_cpp::Device loadANARIDevice()
|
||||
{
|
||||
vtkm::testing::FloatingPointExceptionTrapDisable();
|
||||
auto* libraryName = std::getenv("VTKM_TEST_ANARI_LIBRARY");
|
||||
static bool verbose = std::getenv("VTKM_TEST_ANARI_VERBOSE") != nullptr;
|
||||
auto lib = anari_cpp::loadLibrary(libraryName ? libraryName : "helide", StatusFunc, &verbose);
|
||||
auto d = anari_cpp::newDevice(lib, "default");
|
||||
anari_cpp::unloadLibrary(lib);
|
||||
return d;
|
||||
}
|
||||
|
||||
static void renderTestANARIImage(anari_cpp::Device d,
|
||||
anari_cpp::World w,
|
||||
vtkm::Vec3f_32 cam_pos,
|
||||
vtkm::Vec3f_32 cam_dir,
|
||||
vtkm::Vec3f_32 cam_up,
|
||||
const std::string& imgName,
|
||||
vtkm::Vec2ui_32 imgSize = vtkm::Vec2ui_32(1024, 768))
|
||||
{
|
||||
auto renderer = anari_cpp::newObject<anari_cpp::Renderer>(d, "default");
|
||||
anari_cpp::setParameter(d, renderer, "background", vtkm::Vec4f_32(0.3f, 0.3f, 0.3f, 1.f));
|
||||
anari_cpp::setParameter(d, renderer, "pixelSamples", 64);
|
||||
anari_cpp::commitParameters(d, renderer);
|
||||
|
||||
auto camera = anari_cpp::newObject<anari_cpp::Camera>(d, "perspective");
|
||||
anari_cpp::setParameter(d, camera, "aspect", imgSize[0] / float(imgSize[1]));
|
||||
anari_cpp::setParameter(d, camera, "position", cam_pos);
|
||||
anari_cpp::setParameter(d, camera, "direction", cam_dir);
|
||||
anari_cpp::setParameter(d, camera, "up", cam_up);
|
||||
anari_cpp::commitParameters(d, camera);
|
||||
|
||||
auto frame = anari_cpp::newObject<anari_cpp::Frame>(d);
|
||||
anari_cpp::setParameter(d, frame, "size", imgSize);
|
||||
anari_cpp::setParameter(d, frame, "channel.color", ANARI_FLOAT32_VEC4);
|
||||
anari_cpp::setParameter(d, frame, "world", w);
|
||||
anari_cpp::setParameter(d, frame, "camera", camera);
|
||||
anari_cpp::setParameter(d, frame, "renderer", renderer);
|
||||
anari_cpp::commitParameters(d, frame);
|
||||
|
||||
anari_cpp::release(d, camera);
|
||||
anari_cpp::release(d, renderer);
|
||||
|
||||
anari_cpp::render(d, frame);
|
||||
anari_cpp::wait(d, frame);
|
||||
|
||||
const auto fb = anari_cpp::map<vtkm::Vec4f_32>(d, frame, "channel.color");
|
||||
|
||||
vtkm::cont::DataSetBuilderUniform builder;
|
||||
vtkm::cont::DataSet image = builder.Create(vtkm::Id2(fb.width, fb.height));
|
||||
|
||||
// NOTE: We are only copying the pixel data into a VTK-m array for the
|
||||
// purpose of using VTK-m's image comparison test code. Applications
|
||||
// would not normally do this and instead just use the pixel data
|
||||
// directly, such as displaying it in an interactive window.
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec4f_32> colorArray =
|
||||
vtkm::cont::make_ArrayHandle(fb.data, fb.width * fb.height, vtkm::CopyFlag::On);
|
||||
|
||||
anari_cpp::unmap(d, frame, "channel.color");
|
||||
anari_cpp::release(d, frame);
|
||||
|
||||
image.AddPointField("color", colorArray);
|
||||
|
||||
VTKM_TEST_ASSERT(test_equal_images(image, imgName));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
18
vtkm/interop/anari/testing/CMakeLists.txt
Normal file
18
vtkm/interop/anari/testing/CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
||||
##============================================================================
|
||||
## 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.
|
||||
##============================================================================
|
||||
|
||||
vtkm_unit_tests(
|
||||
SOURCES
|
||||
UnitTestANARIMapperGlyphs.cxx
|
||||
UnitTestANARIMapperPoints.cxx
|
||||
UnitTestANARIMapperTriangles.cxx
|
||||
UnitTestANARIMapperVolume.cxx
|
||||
UnitTestANARIScene.cxx
|
||||
)
|
77
vtkm/interop/anari/testing/UnitTestANARIMapperGlyphs.cxx
Normal file
77
vtkm/interop/anari/testing/UnitTestANARIMapperGlyphs.cxx
Normal file
@ -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.
|
||||
//============================================================================
|
||||
|
||||
// vtkm::anari
|
||||
#include <vtkm/interop/anari/ANARIMapperGlyphs.h>
|
||||
// vtk-m
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
#include <vtkm/filter/vector_analysis/Gradient.h>
|
||||
#include <vtkm/io/EncodePNG.h>
|
||||
#include <vtkm/source/Tangle.h>
|
||||
// std
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
#include "ANARITestCommon.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void RenderTests()
|
||||
{
|
||||
// Initialize ANARI /////////////////////////////////////////////////////////
|
||||
|
||||
auto d = loadANARIDevice();
|
||||
|
||||
// Create VTKm datasets /////////////////////////////////////////////////////
|
||||
|
||||
vtkm::source::Tangle source;
|
||||
source.SetPointDimensions({ 32 });
|
||||
auto tangle = source.Execute();
|
||||
|
||||
vtkm::filter::vector_analysis::Gradient gradientFilter;
|
||||
gradientFilter.SetActiveField("tangle");
|
||||
gradientFilter.SetOutputFieldName("Gradient");
|
||||
auto tangleGrad = gradientFilter.Execute(tangle);
|
||||
|
||||
// Map data to ANARI objects ////////////////////////////////////////////////
|
||||
|
||||
auto world = anari_cpp::newObject<anari_cpp::World>(d);
|
||||
|
||||
vtkm::interop::anari::ANARIActor actor(
|
||||
tangleGrad.GetCellSet(), tangleGrad.GetCoordinateSystem(), tangleGrad.GetField("Gradient"));
|
||||
|
||||
vtkm::interop::anari::ANARIMapperGlyphs mGlyphs(d, actor);
|
||||
|
||||
auto surface = mGlyphs.GetANARISurface();
|
||||
anari_cpp::setParameterArray1D(d, world, "surface", &surface, 1);
|
||||
anari_cpp::commitParameters(d, world);
|
||||
|
||||
// Render a frame ///////////////////////////////////////////////////////////
|
||||
|
||||
renderTestANARIImage(d,
|
||||
world,
|
||||
vtkm::Vec3f_32(0.5f, 1.f, 0.6f),
|
||||
vtkm::Vec3f_32(0.f, -1.f, 0.f),
|
||||
vtkm::Vec3f_32(0.f, 0.f, 1.f),
|
||||
"interop/anari/glyphs.png");
|
||||
|
||||
// Cleanup //////////////////////////////////////////////////////////////////
|
||||
|
||||
anari_cpp::release(d, world);
|
||||
anari_cpp::release(d, d);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int UnitTestANARIMapperGlyphs(int argc, char* argv[])
|
||||
{
|
||||
return vtkm::cont::testing::Testing::Run(RenderTests, argc, argv);
|
||||
}
|
84
vtkm/interop/anari/testing/UnitTestANARIMapperPoints.cxx
Normal file
84
vtkm/interop/anari/testing/UnitTestANARIMapperPoints.cxx
Normal file
@ -0,0 +1,84 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
// vtkm::anari
|
||||
#include <vtkm/interop/anari/ANARIMapperPoints.h>
|
||||
// vtk-m
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
#include <vtkm/filter/contour/Contour.h>
|
||||
#include <vtkm/io/EncodePNG.h>
|
||||
#include <vtkm/source/Tangle.h>
|
||||
// std
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
#include "ANARITestCommon.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void RenderTests()
|
||||
{
|
||||
// Initialize ANARI /////////////////////////////////////////////////////////
|
||||
|
||||
auto d = loadANARIDevice();
|
||||
|
||||
// Create VTKm datasets /////////////////////////////////////////////////////
|
||||
|
||||
vtkm::source::Tangle source;
|
||||
source.SetPointDimensions({ 32 });
|
||||
auto tangle = source.Execute();
|
||||
|
||||
auto& tangle_field = tangle.GetField("tangle");
|
||||
vtkm::Range range;
|
||||
tangle_field.GetRange(&range);
|
||||
const auto isovalue = range.Center();
|
||||
|
||||
vtkm::filter::contour::Contour contourFilter;
|
||||
contourFilter.SetIsoValue(isovalue);
|
||||
contourFilter.SetActiveField("tangle");
|
||||
auto tangleIso = contourFilter.Execute(tangle);
|
||||
|
||||
// Map data to ANARI objects ////////////////////////////////////////////////
|
||||
|
||||
auto world = anari_cpp::newObject<anari_cpp::World>(d);
|
||||
|
||||
vtkm::interop::anari::ANARIActor actor(
|
||||
tangleIso.GetCellSet(), tangleIso.GetCoordinateSystem(), tangleIso.GetField("tangle"));
|
||||
|
||||
vtkm::interop::anari::ANARIMapperPoints mIso(d, actor);
|
||||
setColorMap(d, mIso);
|
||||
|
||||
auto surface = mIso.GetANARISurface();
|
||||
anari_cpp::setParameterArray1D(d, world, "surface", &surface, 1);
|
||||
|
||||
anari_cpp::commitParameters(d, world);
|
||||
|
||||
// Render a frame ///////////////////////////////////////////////////////////
|
||||
|
||||
renderTestANARIImage(d,
|
||||
world,
|
||||
vtkm::Vec3f_32(-0.05, 1.43, 1.87),
|
||||
vtkm::Vec3f_32(0.32, -0.53, -0.79),
|
||||
vtkm::Vec3f_32(-0.20, -0.85, 0.49),
|
||||
"interop/anari/points.png");
|
||||
|
||||
// Cleanup //////////////////////////////////////////////////////////////////
|
||||
|
||||
anari_cpp::release(d, world);
|
||||
anari_cpp::release(d, d);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int UnitTestANARIMapperPoints(int argc, char* argv[])
|
||||
{
|
||||
return vtkm::cont::testing::Testing::Run(RenderTests, argc, argv);
|
||||
}
|
85
vtkm/interop/anari/testing/UnitTestANARIMapperTriangles.cxx
Normal file
85
vtkm/interop/anari/testing/UnitTestANARIMapperTriangles.cxx
Normal file
@ -0,0 +1,85 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
// vtkm::anari
|
||||
#include <vtkm/interop/anari/ANARIMapperTriangles.h>
|
||||
// vtk-m
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
#include <vtkm/filter/contour/Contour.h>
|
||||
#include <vtkm/io/EncodePNG.h>
|
||||
#include <vtkm/source/Tangle.h>
|
||||
// std
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
#include "ANARITestCommon.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void RenderTests()
|
||||
{
|
||||
// Initialize ANARI /////////////////////////////////////////////////////////
|
||||
|
||||
auto d = loadANARIDevice();
|
||||
|
||||
// Create VTKm datasets /////////////////////////////////////////////////////
|
||||
|
||||
vtkm::source::Tangle source;
|
||||
source.SetPointDimensions({ 32 });
|
||||
auto tangle = source.Execute();
|
||||
|
||||
auto& tangle_field = tangle.GetField("tangle");
|
||||
vtkm::Range range;
|
||||
tangle_field.GetRange(&range);
|
||||
const auto isovalue = range.Center();
|
||||
|
||||
vtkm::filter::contour::Contour contourFilter;
|
||||
contourFilter.SetIsoValue(isovalue);
|
||||
contourFilter.SetActiveField("tangle");
|
||||
auto tangleIso = contourFilter.Execute(tangle);
|
||||
|
||||
// Map data to ANARI objects ////////////////////////////////////////////////
|
||||
|
||||
auto world = anari_cpp::newObject<anari_cpp::World>(d);
|
||||
|
||||
vtkm::interop::anari::ANARIActor actor(
|
||||
tangleIso.GetCellSet(), tangleIso.GetCoordinateSystem(), tangleIso.GetField("tangle"));
|
||||
|
||||
vtkm::interop::anari::ANARIMapperTriangles mIso(d, actor);
|
||||
mIso.SetCalculateNormals(true);
|
||||
setColorMap(d, mIso);
|
||||
|
||||
auto surface = mIso.GetANARISurface();
|
||||
anari_cpp::setParameterArray1D(d, world, "surface", &surface, 1);
|
||||
|
||||
anari_cpp::commitParameters(d, world);
|
||||
|
||||
// Render a frame ///////////////////////////////////////////////////////////
|
||||
|
||||
renderTestANARIImage(d,
|
||||
world,
|
||||
vtkm::Vec3f_32(-0.05, 1.43, 1.87),
|
||||
vtkm::Vec3f_32(0.32, -0.53, -0.79),
|
||||
vtkm::Vec3f_32(-0.20, -0.85, 0.49),
|
||||
"interop/anari/isosurface.png");
|
||||
|
||||
// Cleanup //////////////////////////////////////////////////////////////////
|
||||
|
||||
anari_cpp::release(d, world);
|
||||
anari_cpp::release(d, d);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int UnitTestANARIMapperTriangles(int argc, char* argv[])
|
||||
{
|
||||
return vtkm::cont::testing::Testing::Run(RenderTests, argc, argv);
|
||||
}
|
74
vtkm/interop/anari/testing/UnitTestANARIMapperVolume.cxx
Normal file
74
vtkm/interop/anari/testing/UnitTestANARIMapperVolume.cxx
Normal file
@ -0,0 +1,74 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
// vtkm::anari
|
||||
#include <vtkm/interop/anari/ANARIMapperVolume.h>
|
||||
// vtk-m
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
#include <vtkm/filter/contour/Contour.h>
|
||||
#include <vtkm/io/EncodePNG.h>
|
||||
#include <vtkm/source/Tangle.h>
|
||||
// std
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
#include "ANARITestCommon.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void RenderTests()
|
||||
{
|
||||
// Initialize ANARI /////////////////////////////////////////////////////////
|
||||
|
||||
auto d = loadANARIDevice();
|
||||
|
||||
// Create VTKm datasets /////////////////////////////////////////////////////
|
||||
|
||||
vtkm::source::Tangle source;
|
||||
source.SetPointDimensions({ 32 });
|
||||
auto tangle = source.Execute();
|
||||
|
||||
// Map data to ANARI objects ////////////////////////////////////////////////
|
||||
|
||||
auto world = anari_cpp::newObject<anari_cpp::World>(d);
|
||||
|
||||
vtkm::interop::anari::ANARIActor actor(
|
||||
tangle.GetCellSet(), tangle.GetCoordinateSystem(), tangle.GetField("tangle"));
|
||||
|
||||
vtkm::interop::anari::ANARIMapperVolume mVol(d, actor);
|
||||
setColorMap(d, mVol);
|
||||
|
||||
auto volume = mVol.GetANARIVolume();
|
||||
anari_cpp::setParameterArray1D(d, world, "volume", &volume, 1);
|
||||
|
||||
anari_cpp::commitParameters(d, world);
|
||||
|
||||
// Render a frame ///////////////////////////////////////////////////////////
|
||||
|
||||
renderTestANARIImage(d,
|
||||
world,
|
||||
vtkm::Vec3f_32(-0.05, 1.43, 1.87),
|
||||
vtkm::Vec3f_32(0.32, -0.53, -0.79),
|
||||
vtkm::Vec3f_32(-0.20, -0.85, 0.49),
|
||||
"interop/anari/volume.png");
|
||||
|
||||
// Cleanup //////////////////////////////////////////////////////////////////
|
||||
|
||||
anari_cpp::release(d, world);
|
||||
anari_cpp::release(d, d);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int UnitTestANARIMapperVolume(int argc, char* argv[])
|
||||
{
|
||||
return vtkm::cont::testing::Testing::Run(RenderTests, argc, argv);
|
||||
}
|
110
vtkm/interop/anari/testing/UnitTestANARIScene.cxx
Normal file
110
vtkm/interop/anari/testing/UnitTestANARIScene.cxx
Normal file
@ -0,0 +1,110 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
// vtkm::anari
|
||||
#include <vtkm/interop/anari/ANARIMapperGlyphs.h>
|
||||
#include <vtkm/interop/anari/ANARIMapperTriangles.h>
|
||||
#include <vtkm/interop/anari/ANARIMapperVolume.h>
|
||||
#include <vtkm/interop/anari/ANARIScene.h>
|
||||
// vtk-m
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
#include <vtkm/filter/contour/Contour.h>
|
||||
#include <vtkm/filter/vector_analysis/Gradient.h>
|
||||
#include <vtkm/io/EncodePNG.h>
|
||||
#include <vtkm/source/Tangle.h>
|
||||
// std
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
#include "ANARITestCommon.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void RenderTests()
|
||||
{
|
||||
// Initialize ANARI /////////////////////////////////////////////////////////
|
||||
|
||||
auto d = loadANARIDevice();
|
||||
|
||||
// Create VTKm datasets /////////////////////////////////////////////////////
|
||||
|
||||
vtkm::source::Tangle source;
|
||||
source.SetPointDimensions({ 32 });
|
||||
auto tangle = source.Execute();
|
||||
|
||||
auto& tangle_field = tangle.GetField("tangle");
|
||||
vtkm::Range range;
|
||||
tangle_field.GetRange(&range);
|
||||
const auto isovalue = range.Center();
|
||||
|
||||
vtkm::filter::contour::Contour contourFilter;
|
||||
contourFilter.SetIsoValue(isovalue);
|
||||
contourFilter.SetActiveField(tangle_field.GetName());
|
||||
auto tangleIso = contourFilter.Execute(tangle);
|
||||
|
||||
vtkm::filter::vector_analysis::Gradient gradientFilter;
|
||||
gradientFilter.SetActiveField(tangle_field.GetName());
|
||||
gradientFilter.SetOutputFieldName("Gradient");
|
||||
auto tangleGrad = gradientFilter.Execute(tangle);
|
||||
|
||||
// Map data to ANARI objects ////////////////////////////////////////////////
|
||||
|
||||
vtkm::interop::anari::ANARIScene scene(d);
|
||||
|
||||
auto& mVol = scene.AddMapper(vtkm::interop::anari::ANARIMapperVolume(d));
|
||||
mVol.SetName("volume");
|
||||
|
||||
auto& mIso = scene.AddMapper(vtkm::interop::anari::ANARIMapperTriangles(d));
|
||||
mIso.SetName("isosurface");
|
||||
mIso.SetCalculateNormals(true);
|
||||
|
||||
auto& mGrad = scene.AddMapper(vtkm::interop::anari::ANARIMapperGlyphs(d));
|
||||
mGrad.SetName("gradient");
|
||||
|
||||
// Render a frame ///////////////////////////////////////////////////////////
|
||||
|
||||
renderTestANARIImage(d,
|
||||
scene.GetANARIWorld(),
|
||||
vtkm::Vec3f_32(-0.05, 1.43, 1.87),
|
||||
vtkm::Vec3f_32(0.32, -0.53, -0.79),
|
||||
vtkm::Vec3f_32(-0.20, -0.85, 0.49),
|
||||
"interop/anari/scene-empty-mappers.png");
|
||||
|
||||
// Render a frame ///////////////////////////////////////////////////////////
|
||||
|
||||
mVol.SetActor({ tangle.GetCellSet(), tangle.GetCoordinateSystem(), tangle.GetField("tangle") });
|
||||
mIso.SetActor(
|
||||
{ tangleIso.GetCellSet(), tangleIso.GetCoordinateSystem(), tangleIso.GetField("tangle") });
|
||||
mGrad.SetActor(
|
||||
{ tangleGrad.GetCellSet(), tangleGrad.GetCoordinateSystem(), tangleGrad.GetField("Gradient") });
|
||||
|
||||
setColorMap(d, mVol);
|
||||
setColorMap(d, mIso);
|
||||
setColorMap(d, mGrad);
|
||||
|
||||
renderTestANARIImage(d,
|
||||
scene.GetANARIWorld(),
|
||||
vtkm::Vec3f_32(-0.05, 1.43, 1.87),
|
||||
vtkm::Vec3f_32(0.32, -0.53, -0.79),
|
||||
vtkm::Vec3f_32(-0.20, -0.85, 0.49),
|
||||
"interop/anari/scene.png");
|
||||
|
||||
// Cleanup //////////////////////////////////////////////////////////////////
|
||||
|
||||
anari_cpp::release(d, d);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int UnitTestANARIScene(int argc, char* argv[])
|
||||
{
|
||||
return vtkm::cont::testing::Testing::Run(RenderTests, argc, argv);
|
||||
}
|
14
vtkm/interop/anari/vtkm.module
Normal file
14
vtkm/interop/anari/vtkm.module
Normal file
@ -0,0 +1,14 @@
|
||||
NAME
|
||||
vtkm_anari
|
||||
GROUPS
|
||||
ANARI
|
||||
DEPENDS
|
||||
vtkm_filter_field_conversion
|
||||
vtkm_filter_vector_analysis
|
||||
vtkm_rendering
|
||||
vtkm_worklet
|
||||
TEST_DEPENDS
|
||||
vtkm_filter_vector_analysis
|
||||
vtkm_filter_contour
|
||||
vtkm_rendering_testing
|
||||
vtkm_source
|
Loading…
Reference in New Issue
Block a user