#include "hdPrman/volume.h"
#include "hdPrman/context.h"
#include "hdPrman/instancer.h"
#include "hdPrman/material.h"
#include "hdPrman/renderParam.h"
#include "hdPrman/renderPass.h"
#include "hdPrman/rixStrings.h"
#include "pxr/usd/sdf/types.h"
#include "pxr/usdImaging/usdVolImaging/tokens.h"
#include "pxr/base/gf/matrix4f.h"
#include "pxr/base/gf/matrix4d.h"
#include "Riley.h"
#include "RtParamList.h"
#include "RixShadingUtils.h"
#include "RixPredefinedStrings.hpp"
PXR_NAMESPACE_OPEN_SCOPE
HdPrman_Field::HdPrman_Field(TfToken const& typeId, SdfPath const& id)
: HdField(id), _typeId(typeId)
{
}
void HdPrman_Field::Sync(HdSceneDelegate *sceneDelegate,
HdRenderParam *renderParam,
HdDirtyBits *dirtyBits)
{
}
void HdPrman_Field::Finalize(HdRenderParam *renderParam)
{
}
HdDirtyBits HdPrman_Field::GetInitialDirtyBitsMask() const
{
int mask = HdChangeTracker::Clean
| HdChangeTracker::DirtyTransform
| HdChangeTracker::DirtyVisibility
| HdChangeTracker::DirtyPrimvar
| HdChangeTracker::DirtyMaterialId
;
return (HdDirtyBits)mask;
}
HdPrman_Volume::HdPrman_Volume(SdfPath const& id,
SdfPath const& instancerId)
: BASE(id, instancerId)
{
}
HdDirtyBits
HdPrman_Volume::GetInitialDirtyBitsMask() const
{
int mask = HdChangeTracker::Clean
| HdChangeTracker::DirtyTransform
| HdChangeTracker::DirtyVisibility
| HdChangeTracker::DirtyPrimvar
| HdChangeTracker::DirtyMaterialId
| HdChangeTracker::DirtyInstancer
;
return (HdDirtyBits)mask;
}
namespace {
void
_EmitOpenVDBVolume(HdSceneDelegate *sceneDelegate,
const SdfPath& id,
const HdVolumeFieldDescriptorVector& fields,
RtParamList* primvars)
{
static const RtUString blobbydsoImplOpenVDB("blobbydso:impl_openvdb");
if (fields.empty()) {
return;
}
auto const& firstfield = fields[0];
VtValue filePath = sceneDelegate->Get(firstfield.fieldId,
HdFieldTokens->filePath);
SdfAssetPath fileAssetPath = filePath.Get<SdfAssetPath>();
std::string volumeAssetPath = fileAssetPath.GetResolvedPath();
if (volumeAssetPath.empty()) {
volumeAssetPath = fileAssetPath.GetAssetPath();
}
primvars->SetString(RixStr.k_Ri_type, blobbydsoImplOpenVDB);
RtUString sa[2] = {
RtUString(volumeAssetPath.c_str()),
RtUString(firstfield.fieldName.GetText())
};
primvars->SetStringArray(RixStr.k_blobbydso_stringargs, sa, 2);
}
TfToken
_DetermineConsistentFieldPrimType(const HdVolumeFieldDescriptorVector& fields)
{
if (fields.empty()) {
return TfToken();
}
HdVolumeFieldDescriptorVector::const_iterator iter = fields.begin();
TfToken const& fieldPrimType = iter->fieldPrimType;
++iter;
for (; iter != fields.end(); ++iter) {
if (iter->fieldPrimType != fieldPrimType) {
return TfToken();
}
}
return fieldPrimType;
}
enum _FieldType {
FloatType = 0,
ColorType,
PointType,
NormalType,
VectorType
};
_FieldType
_DetermineFieldType(HdVolumeFieldDescriptor const& field)
{
if (field.fieldName.GetString() == "Cd") {
return ColorType;
}
return FloatType;
}
void
_SetupFieldPrimvars(HdVolumeFieldDescriptorVector const& fields,
RtParamList* primvars)
{
for (HdVolumeFieldDescriptor const& field : fields) {
RtUString fieldName = RtUString(field.fieldName.GetText());
RtDetailType detailType = RtDetailType::k_varying;
_FieldType type = _DetermineFieldType(field);
switch (type) {
case FloatType:
primvars->SetFloatDetail(fieldName, nullptr, detailType);
break;
case ColorType:
primvars->SetColorDetail(fieldName, nullptr, detailType);
break;
case PointType:
primvars->SetPointDetail(fieldName, nullptr, detailType);
break;
case NormalType:
primvars->SetNormalDetail(fieldName, nullptr, detailType);
break;
case VectorType:
primvars->SetVectorDetail(fieldName, nullptr, detailType);
break;
}
}
}
}
HdPrman_Volume::_VolumeEmitterMap&
HdPrman_Volume::_GetVolumeEmitterMap()
{
static _VolumeEmitterMap volumeEmitters = {
{UsdVolImagingTokens->openvdbAsset, _EmitOpenVDBVolume}
};
return volumeEmitters;
}
bool
HdPrman_Volume::AddVolumeTypeEmitter(TfToken const& fieldPrimType,
HdPrman_VolumeTypeEmitter emitterFunc,
bool overrideExisting)
{
auto pair = _GetVolumeEmitterMap().insert({fieldPrimType, emitterFunc});
if (overrideExisting || pair.second) {
pair.first->second = emitterFunc;
return true;
}
return false;
}
RtParamList
HdPrman_Volume::_ConvertGeometry(HdPrman_Context *context,
HdSceneDelegate *sceneDelegate,
const SdfPath &id,
RtUString *primType,
std::vector<HdGeomSubset> *geomSubsets)
{
HdVolumeFieldDescriptorVector fields =
sceneDelegate->GetVolumeFieldDescriptors(id);
if (fields.empty()) {
return RtParamList();
}
TfToken fieldPrimType = _DetermineConsistentFieldPrimType(fields);
if (fieldPrimType.IsEmpty()) {
TF_WARN("The fields on volume %s have inconsistent types and can't be "
"emitted as a single volume", id.GetText());
return RtParamList();
}
_VolumeEmitterMap const& volumeEmitters = _GetVolumeEmitterMap();
auto const iter = volumeEmitters.find(fieldPrimType);
if (iter == volumeEmitters.end()) {
TF_WARN("No volume emitter registered for field type '%s' "
"on prim %s", fieldPrimType.GetText(), id.GetText());
return RtParamList();
}
int32_t const dims[] = { 0, 0, 0 };
uint64_t const dim = dims[0] * dims[1] * dims[2];
RtParamList primvars(1, dim, dim, dim);
primvars.SetIntegerArray(RixStr.k_Ri_dimensions, dims, 3);
*primType = RixStr.k_Ri_Volume;
HdPrman_VolumeTypeEmitter emitterFunc = iter->second;
emitterFunc(sceneDelegate, id, fields, &primvars);
_SetupFieldPrimvars(fields, &primvars);
HdPrman_ConvertPrimvars(sceneDelegate, id, primvars, 1, dim, dim, dim);
return primvars;
}
PXR_NAMESPACE_CLOSE_SCOPE