mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-10-05 09:59:12 +00:00
328 lines
9.2 KiB
C++
328 lines
9.2 KiB
C++
//============================================================================
|
|
// Copyright (c) Kitware, Inc.
|
|
// All rights reserved.
|
|
// See LICENSE.txt for details.
|
|
//
|
|
// This software is distributed WITHOUT ANY WARRANTY; without even
|
|
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
// PURPOSE. See the above copyright notice for more information.
|
|
//============================================================================
|
|
#include <vtkm/rendering/raytracing/ScalarRenderer.h>
|
|
|
|
#include <iostream>
|
|
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
|
|
#include <vtkm/cont/Timer.h>
|
|
|
|
#include <vtkm/rendering/raytracing/Logger.h>
|
|
#include <vtkm/rendering/raytracing/RayTracingTypeDefs.h>
|
|
#include <vtkm/worklet/WorkletMapField.h>
|
|
|
|
namespace vtkm
|
|
{
|
|
namespace rendering
|
|
{
|
|
namespace raytracing
|
|
{
|
|
|
|
namespace detail
|
|
{
|
|
|
|
template <typename Precision>
|
|
class SurfaceShade
|
|
{
|
|
public:
|
|
class Shade : public vtkm::worklet::WorkletMapField
|
|
{
|
|
private:
|
|
vtkm::Vec3f_32 LightPosition;
|
|
vtkm::Vec3f_32 LightAmbient{ .5f, .5f, .5f };
|
|
vtkm::Vec3f_32 LightDiffuse{ .7f, .7f, .7f };
|
|
vtkm::Vec3f_32 LightSpecular{ .7f, .7f, .7f };
|
|
vtkm::Float32 SpecularExponent = 20.f;
|
|
vtkm::Vec3f_32 CameraPosition;
|
|
vtkm::Vec3f_32 LookAt;
|
|
Precision MissScalar;
|
|
|
|
public:
|
|
VTKM_CONT
|
|
Shade(const vtkm::Vec3f_32& lightPosition,
|
|
const vtkm::Vec3f_32& cameraPosition,
|
|
const vtkm::Vec3f_32& lookAt,
|
|
const Precision missScalar)
|
|
: LightPosition(lightPosition)
|
|
, CameraPosition(cameraPosition)
|
|
, LookAt(lookAt)
|
|
, MissScalar(missScalar)
|
|
{
|
|
}
|
|
|
|
using ControlSignature = void(FieldIn, FieldIn, FieldIn, FieldOut);
|
|
using ExecutionSignature = void(_1, _2, _3, _4);
|
|
|
|
VTKM_EXEC void operator()(const vtkm::Id& hitIdx,
|
|
const vtkm::Vec<Precision, 3>& normal,
|
|
const vtkm::Vec<Precision, 3>& intersection,
|
|
Precision& output) const
|
|
{
|
|
if (hitIdx < 0)
|
|
{
|
|
output = MissScalar;
|
|
}
|
|
|
|
vtkm::Vec<Precision, 3> lightDir = LightPosition - intersection;
|
|
vtkm::Vec<Precision, 3> viewDir = CameraPosition - LookAt;
|
|
vtkm::Normalize(lightDir);
|
|
vtkm::Normalize(viewDir);
|
|
//Diffuse lighting
|
|
Precision cosTheta = vtkm::dot(normal, lightDir);
|
|
//clamp tp [0,1]
|
|
const Precision zero = 0.f;
|
|
const Precision one = 1.f;
|
|
cosTheta = vtkm::Min(vtkm::Max(cosTheta, zero), one);
|
|
//Specular lighting
|
|
vtkm::Vec<Precision, 3> reflect = 2.f * vtkm::dot(lightDir, normal) * normal - lightDir;
|
|
vtkm::Normalize(reflect);
|
|
Precision cosPhi = vtkm::dot(reflect, viewDir);
|
|
Precision specularConstant =
|
|
vtkm::Pow(vtkm::Max(cosPhi, zero), static_cast<Precision>(SpecularExponent));
|
|
|
|
Precision shade = vtkm::Min(
|
|
LightAmbient[0] + LightDiffuse[0] * cosTheta + LightSpecular[0] * specularConstant, one);
|
|
output = shade;
|
|
}
|
|
|
|
vtkm::Vec3f_32 GetDiffuse() { return LightDiffuse; }
|
|
|
|
vtkm::Vec3f_32 GetAmbient() { return LightAmbient; }
|
|
|
|
vtkm::Vec3f_32 GetSpecular() { return LightSpecular; }
|
|
|
|
vtkm::Float32 GetSpecularExponent() { return SpecularExponent; }
|
|
|
|
|
|
void SetDiffuse(vtkm::Vec3f_32 newDiffuse)
|
|
{
|
|
LightDiffuse[0] = newDiffuse[0];
|
|
LightDiffuse[1] = newDiffuse[1];
|
|
LightDiffuse[2] = newDiffuse[2];
|
|
}
|
|
|
|
void SetAmbient(vtkm::Vec3f_32 newAmbient)
|
|
{
|
|
LightAmbient[0] = newAmbient[0];
|
|
LightAmbient[1] = newAmbient[1];
|
|
LightAmbient[2] = newAmbient[2];
|
|
}
|
|
|
|
void SetSpecular(vtkm::Vec3f_32 newSpecular)
|
|
{
|
|
LightSpecular[0] = newSpecular[0];
|
|
LightSpecular[1] = newSpecular[1];
|
|
LightSpecular[2] = newSpecular[2];
|
|
}
|
|
|
|
void SetSpecularExponent(vtkm::Float32 newExponent) { SpecularExponent = newExponent; }
|
|
|
|
|
|
}; //class Shade
|
|
|
|
VTKM_CONT void run(Ray<Precision>& rays,
|
|
const vtkm::rendering::raytracing::Camera& camera,
|
|
const Precision missScalar,
|
|
vtkm::cont::ArrayHandle<Precision> shadings,
|
|
bool shade)
|
|
{
|
|
if (shade)
|
|
{
|
|
// TODO: support light positions
|
|
vtkm::Vec3f_32 scale(2, 2, 2);
|
|
vtkm::Vec3f_32 lightPosition = camera.GetPosition() + scale * camera.GetUp();
|
|
vtkm::worklet::DispatcherMapField<Shade>(
|
|
Shade(lightPosition, camera.GetPosition(), camera.GetLookAt(), missScalar))
|
|
.Invoke(rays.HitIdx, rays.Normal, rays.Intersection, shadings);
|
|
}
|
|
}
|
|
}; // class SurfaceShade
|
|
|
|
|
|
template <typename Precision>
|
|
class FilterDepth : public vtkm::worklet::WorkletMapField
|
|
{
|
|
private:
|
|
Precision MissScalar;
|
|
|
|
public:
|
|
VTKM_CONT
|
|
explicit FilterDepth(const Precision missScalar)
|
|
: MissScalar(missScalar)
|
|
{
|
|
}
|
|
|
|
typedef void ControlSignature(FieldIn, FieldInOut);
|
|
|
|
typedef void ExecutionSignature(_1, _2);
|
|
VTKM_EXEC void operator()(const vtkm::Id& hitIndex, Precision& scalar) const
|
|
{
|
|
Precision value = scalar;
|
|
if (hitIndex < 0)
|
|
{
|
|
value = MissScalar;
|
|
}
|
|
|
|
scalar = value;
|
|
}
|
|
}; //class FilterDepth
|
|
|
|
template <typename Precision>
|
|
class WriteBuffer : public vtkm::worklet::WorkletMapField
|
|
{
|
|
private:
|
|
Precision MissScalar;
|
|
|
|
public:
|
|
VTKM_CONT
|
|
explicit WriteBuffer(const Precision missScalar)
|
|
: MissScalar(missScalar)
|
|
{
|
|
}
|
|
|
|
typedef void ControlSignature(FieldIn, FieldIn, FieldOut);
|
|
|
|
typedef void ExecutionSignature(_1, _2, _3);
|
|
VTKM_EXEC void operator()(const vtkm::Id& hitIndex,
|
|
const Precision& scalar,
|
|
Precision& output) const
|
|
{
|
|
Precision value = scalar;
|
|
if (hitIndex < 0)
|
|
{
|
|
value = MissScalar;
|
|
}
|
|
|
|
output = value;
|
|
}
|
|
}; //class WriteBuffer
|
|
|
|
template <typename Precision>
|
|
class WriteDepthBuffer : public vtkm::worklet::WorkletMapField
|
|
{
|
|
public:
|
|
typedef void ControlSignature(FieldIn, FieldOut);
|
|
|
|
typedef void ExecutionSignature(_1, _2);
|
|
VTKM_EXEC void operator()(const Precision& depth, Precision& output) const { output = depth; }
|
|
}; //class WriteDepthBuffer
|
|
} // namespace detail
|
|
|
|
void ScalarRenderer::SetShapeIntersector(std::unique_ptr<ShapeIntersector>&& intersector)
|
|
{
|
|
Intersector = std::move(intersector);
|
|
}
|
|
|
|
void ScalarRenderer::AddField(const vtkm::cont::Field& scalarField)
|
|
{
|
|
const auto& ranges = scalarField.GetRange();
|
|
if (ranges.GetNumberOfValues() != 1)
|
|
{
|
|
throw vtkm::cont::ErrorBadValue("ScalarRenderer(AddField): field must be a scalar");
|
|
}
|
|
Fields.push_back(scalarField);
|
|
}
|
|
|
|
void ScalarRenderer::Render(Ray<vtkm::Float32>& rays,
|
|
vtkm::Float32 missScalar,
|
|
vtkm::rendering::raytracing::Camera& cam)
|
|
{
|
|
RenderOnDevice(rays, missScalar, cam);
|
|
}
|
|
|
|
void ScalarRenderer::Render(Ray<vtkm::Float64>& rays,
|
|
vtkm::Float64 missScalar,
|
|
vtkm::rendering::raytracing::Camera& cam)
|
|
{
|
|
RenderOnDevice(rays, missScalar, cam);
|
|
}
|
|
|
|
template <typename Precision>
|
|
void ScalarRenderer::RenderOnDevice(Ray<Precision>& rays,
|
|
Precision missScalar,
|
|
vtkm::rendering::raytracing::Camera& cam)
|
|
{
|
|
using Timer = vtkm::cont::Timer;
|
|
|
|
Logger* logger = Logger::GetInstance();
|
|
Timer renderTimer;
|
|
renderTimer.Start();
|
|
vtkm::Float64 time = 0.;
|
|
logger->OpenLogEntry("scalar_renderer");
|
|
logger->AddLogData("device", GetDeviceString());
|
|
|
|
logger->AddLogData("num_rays", rays.NumRays);
|
|
const size_t numFields = Fields.size();
|
|
|
|
if (numFields == 0)
|
|
{
|
|
throw vtkm::cont::ErrorBadValue("ScalarRenderer: no fields added");
|
|
}
|
|
if (!Intersector)
|
|
{
|
|
throw vtkm::cont::ErrorBadValue("ScalarRenderer: intersector never set");
|
|
}
|
|
|
|
Timer timer;
|
|
timer.Start();
|
|
|
|
Intersector->IntersectRays(rays);
|
|
time = timer.GetElapsedTime();
|
|
logger->AddLogData("intersect", time);
|
|
|
|
for (size_t f = 0; f < numFields; ++f)
|
|
{
|
|
timer.Start();
|
|
Intersector->IntersectionData(rays, Fields[f]);
|
|
time = timer.GetElapsedTime();
|
|
logger->AddLogData("intersection_data", time);
|
|
AddBuffer(rays, missScalar, Fields[f].GetName());
|
|
}
|
|
|
|
const vtkm::Int32 numChannels = 1;
|
|
ChannelBuffer<Precision> buffer(numChannels, rays.NumRays);
|
|
detail::SurfaceShade<Precision> surfaceShade;
|
|
surfaceShade.run(rays, cam, missScalar, buffer.Buffer, true);
|
|
buffer.SetName("shading");
|
|
rays.Buffers.push_back(buffer);
|
|
|
|
this->Invoke(detail::FilterDepth<Precision>{ missScalar }, rays.HitIdx, rays.Distance);
|
|
|
|
time = renderTimer.GetElapsedTime();
|
|
logger->CloseLogEntry(time);
|
|
} // RenderOnDevice
|
|
|
|
template <typename Precision>
|
|
void ScalarRenderer::AddBuffer(Ray<Precision>& rays, Precision missScalar, const std::string& name)
|
|
{
|
|
const vtkm::Int32 numChannels = 1;
|
|
ChannelBuffer<Precision> buffer(numChannels, rays.NumRays);
|
|
|
|
this->Invoke(
|
|
detail::WriteBuffer<Precision>{ missScalar }, rays.HitIdx, rays.Scalar, buffer.Buffer);
|
|
|
|
buffer.SetName(name);
|
|
rays.Buffers.push_back(buffer);
|
|
}
|
|
|
|
template <typename Precision>
|
|
void ScalarRenderer::AddDepthBuffer(Ray<Precision>& rays)
|
|
{
|
|
const vtkm::Int32 numChannels = 1;
|
|
ChannelBuffer<Precision> buffer(numChannels, rays.NumRays);
|
|
|
|
this->Invoke(detail::WriteDepthBuffer<Precision>{}, rays.Depth, buffer.Buffer);
|
|
|
|
buffer.SetName("depth");
|
|
rays.Buffers.push_back(buffer);
|
|
}
|
|
}
|
|
}
|
|
} // namespace vtkm::rendering::raytracing
|