/* SPDX-License-Identifier: Apache-2.0 * Copyright 2022 NVIDIA Corporation * Copyright 2022 Blender Foundation */ #include "hydra/node_util.h" #include "util/transform.h" #include #include #include #include #include #include #include #include HDCYCLES_NAMESPACE_OPEN_SCOPE namespace { template DstType convertToCycles(const VtValue &value) { if (value.IsHolding()) { return value.UncheckedGet(); } VtValue castedValue = VtValue::Cast(value); if (castedValue.IsHolding()) { return castedValue.UncheckedGet(); } TF_WARN("Could not convert VtValue to Cycles type"); return DstType(0); } template<> float2 convertToCycles(const VtValue &value) { const GfVec2f convertedValue = convertToCycles(value); return make_float2(convertedValue[0], convertedValue[1]); } template<> float3 convertToCycles(const VtValue &value) { if (value.IsHolding()) { const GfVec3f convertedValue = value.UncheckedGet(); return make_float3(convertedValue[0], convertedValue[1], convertedValue[2]); } if (value.IsHolding()) { const GfVec4f convertedValue = value.UncheckedGet(); return make_float3(convertedValue[0], convertedValue[1], convertedValue[2]); } if (value.CanCast()) { const GfVec3f convertedValue = VtValue::Cast(value).UncheckedGet(); return make_float3(convertedValue[0], convertedValue[1], convertedValue[2]); } if (value.CanCast()) { const GfVec4f convertedValue = VtValue::Cast(value).UncheckedGet(); return make_float3(convertedValue[0], convertedValue[1], convertedValue[2]); } TF_WARN("Could not convert VtValue to float3"); return zero_float3(); } template<> ustring convertToCycles(const VtValue &value) { if (value.IsHolding()) { return ustring(value.UncheckedGet().GetString()); } if (value.IsHolding()) { return ustring(value.UncheckedGet()); } if (value.IsHolding()) { const SdfAssetPath &path = value.UncheckedGet(); return ustring(path.GetResolvedPath()); } if (value.CanCast()) { return convertToCycles(VtValue::Cast(value)); } if (value.CanCast()) { return convertToCycles(VtValue::Cast(value)); } if (value.CanCast()) { return convertToCycles(VtValue::Cast(value)); } TF_WARN("Could not convert VtValue to ustring"); return ustring(); } template Transform convertMatrixToCycles( const typename std::enable_if::type &matrix) { return make_transform(matrix[0][0], matrix[1][0], matrix[2][0], 0, matrix[0][1], matrix[1][1], matrix[2][1], 0, matrix[0][2], matrix[1][2], matrix[2][2], 0); } template Transform convertMatrixToCycles( const typename std::enable_if::type &matrix) { return make_transform(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0], matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1], matrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2]); } template<> Transform convertToCycles(const VtValue &value) { if (value.IsHolding()) { return convertMatrixToCycles(value.UncheckedGet()); } if (value.IsHolding()) { return convertMatrixToCycles(value.UncheckedGet()); } if (value.IsHolding()) { return convertMatrixToCycles(value.UncheckedGet()); } if (value.IsHolding()) { return convertMatrixToCycles(value.UncheckedGet()); } if (value.CanCast()) { return convertToCycles(VtValue::Cast(value)); } if (value.CanCast()) { return convertToCycles(VtValue::Cast(value)); } if (value.CanCast()) { return convertToCycles(VtValue::Cast(value)); } if (value.CanCast()) { return convertToCycles(VtValue::Cast(value)); } TF_WARN("Could not convert VtValue to Transform"); return transform_identity(); } template array convertToCyclesArray(const VtValue &value) { static_assert(sizeof(DstType) == sizeof(SrcType), "Size mismatch between VtArray and array base type"); using SrcArray = VtArray; if (value.IsHolding()) { const auto &valueData = value.UncheckedGet(); array cyclesArray; cyclesArray.resize(valueData.size()); std::memcpy(cyclesArray.data(), valueData.data(), valueData.size() * sizeof(DstType)); return cyclesArray; } if (value.CanCast()) { VtValue castedValue = VtValue::Cast(value); const auto &valueData = castedValue.UncheckedGet(); array cyclesArray; cyclesArray.resize(valueData.size()); std::memcpy(cyclesArray.data(), valueData.data(), valueData.size() * sizeof(DstType)); return cyclesArray; } return array(); } template<> array convertToCyclesArray(const VtValue &value) { if (value.IsHolding()) { const auto &valueData = value.UncheckedGet(); array cyclesArray; cyclesArray.reserve(valueData.size()); for (const GfVec3f &vec : valueData) { cyclesArray.push_back_reserved(make_float3(vec[0], vec[1], vec[2])); } return cyclesArray; } if (value.IsHolding()) { const auto &valueData = value.UncheckedGet(); array cyclesArray; cyclesArray.reserve(valueData.size()); for (const GfVec4f &vec : valueData) { cyclesArray.push_back_reserved(make_float3(vec[0], vec[1], vec[2])); } return cyclesArray; } if (value.CanCast()) { return convertToCyclesArray(VtValue::Cast(value)); } if (value.CanCast()) { return convertToCyclesArray(VtValue::Cast(value)); } return array(); } template<> array convertToCyclesArray(const VtValue &value) { using SdfPathArray = VtArray; if (value.IsHolding()) { const auto &valueData = value.UncheckedGet(); array cyclesArray; cyclesArray.reserve(valueData.size()); for (const auto &element : valueData) { cyclesArray.push_back_reserved(ustring(element)); } return cyclesArray; } if (value.IsHolding()) { const auto &valueData = value.UncheckedGet(); array cyclesArray; cyclesArray.reserve(valueData.size()); for (const auto &element : valueData) { cyclesArray.push_back_reserved(ustring(element.GetString())); } return cyclesArray; } if (value.IsHolding()) { const auto &valueData = value.UncheckedGet(); array cyclesArray; cyclesArray.reserve(valueData.size()); for (const auto &element : valueData) { cyclesArray.push_back_reserved(ustring(element.GetResolvedPath())); } return cyclesArray; } if (value.CanCast()) { return convertToCyclesArray(VtValue::Cast(value)); } if (value.CanCast()) { return convertToCyclesArray(VtValue::Cast(value)); } if (value.CanCast()) { return convertToCyclesArray(VtValue::Cast(value)); } TF_WARN("Could not convert VtValue to array"); return array(); } template array convertToCyclesTransformArray(const VtValue &value) { assert(value.IsHolding()); const auto &valueData = value.UncheckedGet(); array cyclesArray; cyclesArray.reserve(valueData.size()); for (const auto &element : valueData) { cyclesArray.push_back_reserved( convertMatrixToCycles(element)); } return cyclesArray; } template<> array convertToCyclesArray(const VtValue &value) { if (value.IsHolding()) { return convertToCyclesTransformArray(value); } if (value.IsHolding()) { return convertToCyclesTransformArray(value); } if (value.IsHolding()) { return convertToCyclesTransformArray(value); } if (value.IsHolding()) { return convertToCyclesTransformArray(value); } if (value.CanCast()) { return convertToCyclesTransformArray(VtValue::Cast(value)); } if (value.CanCast()) { return convertToCyclesTransformArray(VtValue::Cast(value)); } if (value.CanCast()) { return convertToCyclesTransformArray(VtValue::Cast(value)); } if (value.CanCast()) { return convertToCyclesTransformArray(VtValue::Cast(value)); } TF_WARN("Could not convert VtValue to array"); return array(); } template VtValue convertFromCycles(const SrcType &value) { return VtValue(value); } template<> VtValue convertFromCycles(const float2 &value) { const GfVec2f convertedValue(value.x, value.y); return VtValue(convertedValue); } template<> VtValue convertFromCycles(const float3 &value) { const GfVec3f convertedValue(value.x, value.y, value.z); return VtValue(convertedValue); } template<> VtValue convertFromCycles(const ustring &value) { return VtValue(value.string()); } GfMatrix4f convertMatrixFromCycles(const Transform &matrix) { return GfMatrix4f(matrix[0][0], matrix[1][0], matrix[2][0], 0.0f, matrix[0][1], matrix[1][1], matrix[2][1], 0.0f, matrix[0][2], matrix[1][2], matrix[2][2], 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); } template<> VtValue convertFromCycles(const Transform &value) { return VtValue(convertMatrixFromCycles(value)); } template VtValue convertFromCyclesArray(const array &value) { static_assert(sizeof(DstType) == sizeof(SrcType), "Size mismatch between VtArray and array base type"); VtArray convertedValue; convertedValue.resize(value.size()); std::memcpy(convertedValue.data(), value.data(), value.size() * sizeof(SrcType)); return VtValue(convertedValue); } template<> VtValue convertFromCyclesArray(const array &value) { VtVec3fArray convertedValue; convertedValue.reserve(value.size()); for (const auto &element : value) { convertedValue.push_back(GfVec3f(element.x, element.y, element.z)); } return VtValue(convertedValue); } template<> VtValue convertFromCyclesArray(const array &value) { VtStringArray convertedValue; convertedValue.reserve(value.size()); for (const auto &element : value) { convertedValue.push_back(element.string()); } return VtValue(convertedValue); } template<> VtValue convertFromCyclesArray(const array &value) { VtMatrix4fArray convertedValue; convertedValue.reserve(value.size()); for (const auto &element : value) { convertedValue.push_back(convertMatrixFromCycles(element)); } return VtValue(convertedValue); } } // namespace void SetNodeValue(Node *node, const SocketType &socket, const VtValue &value) { switch (socket.type) { default: case SocketType::UNDEFINED: TF_RUNTIME_ERROR("Unexpected conversion: SocketType::UNDEFINED"); break; case SocketType::BOOLEAN: node->set(socket, convertToCycles(value)); break; case SocketType::FLOAT: node->set(socket, convertToCycles(value)); break; case SocketType::INT: node->set(socket, convertToCycles(value)); break; case SocketType::UINT: node->set(socket, convertToCycles(value)); break; case SocketType::COLOR: case SocketType::VECTOR: case SocketType::POINT: case SocketType::NORMAL: node->set(socket, convertToCycles(value)); break; case SocketType::POINT2: node->set(socket, convertToCycles(value)); break; case SocketType::CLOSURE: // Handled by node connections break; case SocketType::STRING: node->set(socket, convertToCycles(value)); break; case SocketType::ENUM: // Enum's can accept a string or an int if (value.IsHolding() || value.IsHolding()) { node->set(socket, convertToCycles(value)); } else { node->set(socket, convertToCycles(value)); } break; case SocketType::TRANSFORM: node->set(socket, convertToCycles(value)); break; case SocketType::NODE: // TODO: renderIndex->GetRprim()->cycles_node ? TF_WARN("Unimplemented conversion: SocketType::NODE"); break; case SocketType::BOOLEAN_ARRAY: { auto cyclesArray = convertToCyclesArray(value); node->set(socket, cyclesArray); break; } case SocketType::FLOAT_ARRAY: { auto cyclesArray = convertToCyclesArray(value); node->set(socket, cyclesArray); break; } case SocketType::INT_ARRAY: { auto cyclesArray = convertToCyclesArray(value); node->set(socket, cyclesArray); break; } case SocketType::COLOR_ARRAY: case SocketType::VECTOR_ARRAY: case SocketType::POINT_ARRAY: case SocketType::NORMAL_ARRAY: { auto cyclesArray = convertToCyclesArray(value); node->set(socket, cyclesArray); break; } case SocketType::POINT2_ARRAY: { auto cyclesArray = convertToCyclesArray(value); node->set(socket, cyclesArray); break; } case SocketType::STRING_ARRAY: { auto cyclesArray = convertToCyclesArray(value); node->set(socket, cyclesArray); break; } case SocketType::TRANSFORM_ARRAY: { auto cyclesArray = convertToCyclesArray(value); node->set(socket, cyclesArray); break; } case SocketType::NODE_ARRAY: { // TODO: renderIndex->GetRprim()->cycles_node ? TF_WARN("Unimplemented conversion: SocketType::NODE_ARRAY"); break; } } } VtValue GetNodeValue(const Node *node, const SocketType &socket) { switch (socket.type) { default: case SocketType::UNDEFINED: TF_RUNTIME_ERROR("Unexpected conversion: SocketType::UNDEFINED"); return VtValue(); case SocketType::BOOLEAN: return convertFromCycles(node->get_bool(socket)); case SocketType::FLOAT: return convertFromCycles(node->get_float(socket)); case SocketType::INT: return convertFromCycles(node->get_int(socket)); case SocketType::UINT: return convertFromCycles(node->get_uint(socket)); case SocketType::COLOR: case SocketType::VECTOR: case SocketType::POINT: case SocketType::NORMAL: return convertFromCycles(node->get_float3(socket)); case SocketType::POINT2: return convertFromCycles(node->get_float2(socket)); case SocketType::CLOSURE: return VtValue(); case SocketType::STRING: return convertFromCycles(node->get_string(socket)); case SocketType::ENUM: return convertFromCycles(node->get_int(socket)); case SocketType::TRANSFORM: return convertFromCycles(node->get_transform(socket)); case SocketType::NODE: TF_WARN("Unimplemented conversion: SocketType::NODE"); return VtValue(); case SocketType::BOOLEAN_ARRAY: return convertFromCyclesArray(node->get_bool_array(socket)); case SocketType::FLOAT_ARRAY: return convertFromCyclesArray(node->get_float_array(socket)); case SocketType::INT_ARRAY: return convertFromCyclesArray(node->get_int_array(socket)); case SocketType::COLOR_ARRAY: case SocketType::VECTOR_ARRAY: case SocketType::POINT_ARRAY: case SocketType::NORMAL_ARRAY: return convertFromCyclesArray(node->get_float3_array(socket)); case SocketType::POINT2_ARRAY: return convertFromCyclesArray(node->get_float2_array(socket)); case SocketType::STRING_ARRAY: return convertFromCyclesArray(node->get_string_array(socket)); case SocketType::TRANSFORM_ARRAY: return convertFromCyclesArray(node->get_transform_array(socket)); case SocketType::NODE_ARRAY: { TF_WARN("Unimplemented conversion: SocketType::NODE_ARRAY"); return VtValue(); } } } HDCYCLES_NAMESPACE_CLOSE_SCOPE