From a685d60975d56a20536cecbe375dff842d247d20 Mon Sep 17 00:00:00 2001 From: cpichard Date: Fri, 5 Jan 2024 14:02:44 +0000 Subject: [PATCH] handle vertex interpolated uvs on bspline curves (#1792) --- CHANGELOG.md | 1 + libs/render_delegate/basis_curves.cpp | 63 +++++++++++-------- testsuite/groups | 2 +- testsuite/test_1769/README | 7 +++ testsuite/test_1769/data/test.usda | 83 ++++++++++++++++++++++++++ testsuite/test_1769/ref/reference.tif | Bin 0 -> 4101 bytes 6 files changed, 129 insertions(+), 27 deletions(-) create mode 100644 testsuite/test_1769/README create mode 100644 testsuite/test_1769/data/test.usda create mode 100644 testsuite/test_1769/ref/reference.tif diff --git a/CHANGELOG.md b/CHANGELOG.md index 92d791edb6..a3f7a4321c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Bug fixes - [usd#1776](https://github.com/Autodesk/arnold-usd/issues/1776) - Fix incorrect PointInstancer instance orientations in the render delegate. +- [usd#1769](https://github.com/Autodesk/arnold-usd/issues/1769) - Fix curve uvs when they are vertex interpolated. ## [7.2.5.0] - 2023-12-13 diff --git a/libs/render_delegate/basis_curves.cpp b/libs/render_delegate/basis_curves.cpp index f01120d47c..2fe36ab04e 100644 --- a/libs/render_delegate/basis_curves.cpp +++ b/libs/render_delegate/basis_curves.cpp @@ -53,6 +53,30 @@ namespace { } // namespace + +// Function to convert a GfVec3f array to a GfVec2f array, skipping the last component. +// It could be used more generally later by registering it as a VtValue Cast: +// +// VtValue::RegisterCast(&Vec3fToVec2f); +// +// then simply call the Cast function as follows: +// +// value = VtValue::Cast(desc.value); +// +VtValue Vec3fToVec2f(VtValue const &val) { + if (val.IsHolding()) { + const auto& vec3 = val.UncheckedGet(); + VtVec2fArray vec2(vec3.size()); + std::transform( + vec3.cbegin(), vec3.cend(), vec2.begin(), + [](const GfVec3f& in) -> GfVec2f { + return {in[0], in[1]}; + }); + return VtValue::Take(vec2); + } + return {}; +} + #if PXR_VERSION >= 2102 HdArnoldBasisCurves::HdArnoldBasisCurves(HdArnoldRenderDelegate* delegate, const SdfPath& id) : HdArnoldRprim(str::curves, delegate, id), _interpolation(HdTokens->linear) @@ -187,28 +211,16 @@ void HdArnoldBasisCurves::Sync( } continue; } + + // The curves node only knows the "uvs" parameter, so we have to rename the attribute + TfToken arnoldAttributeName = primvar.first; + auto value = desc.value; if (primvar.first == str::t_uv || primvar.first == str::t_st) { - // This is either a VtVec2fArray or VtVec3fArray (in Solaris). - if (desc.value.IsHolding()) { - const auto& v = desc.value.UncheckedGet(); - AiNodeSetArray( - GetArnoldNode(), str::uvs, AiArrayConvert(v.size(), 1, AI_TYPE_VECTOR2, v.data())); - continue; - } + arnoldAttributeName = str::t_uvs; + // Special case if the uvs attribute has 3 dimensions if (desc.value.IsHolding()) { - const auto& v = desc.value.UncheckedGet(); - auto* arr = AiArrayAllocate(v.size(), 1, AI_TYPE_VECTOR2); - if (!v.empty()) { - std::transform( - v.begin(), v.end(), static_cast(AiArrayMap(arr)), - [](const GfVec3f& in) -> GfVec2f { - return {in[0], in[1]}; - }); - AiArrayUnmap(arr); - } - AiNodeSetArray(GetArnoldNode(), str::uvs, arr); - continue; - } + value = Vec3fToVec2f(desc.value); + } } if (desc.interpolation == HdInterpolationConstant) { @@ -216,21 +228,20 @@ void HdArnoldBasisCurves::Sync( // all the primvars. if (primvar.first != _tokens->basis) { HdArnoldSetConstantPrimvar( - GetArnoldNode(), primvar.first, desc.role, desc.value, &_visibilityFlags, &_sidednessFlags, + GetArnoldNode(), arnoldAttributeName, desc.role, value, &_visibilityFlags, &_sidednessFlags, nullptr, GetRenderDelegate()); } } else if (desc.interpolation == HdInterpolationUniform) { - HdArnoldSetUniformPrimvar(GetArnoldNode(), primvar.first, desc.role, desc.value); + HdArnoldSetUniformPrimvar(GetArnoldNode(), arnoldAttributeName, desc.role, value); } else if (desc.interpolation == HdInterpolationVertex || desc.interpolation == HdInterpolationVarying) { if (primvar.first == HdTokens->points) { - HdArnoldSetPositionFromValue(GetArnoldNode(), str::points, desc.value); + HdArnoldSetPositionFromValue(GetArnoldNode(), str::points, value); } else if (primvar.first == HdTokens->normals) { if (_interpolation == HdTokens->linear) AiMsgWarning("%s : Orientations not supported on linear curves", AiNodeGetName(GetArnoldNode())); else - curvesData.SetOrientationFromValue(GetArnoldNode(), desc.value); + curvesData.SetOrientationFromValue(GetArnoldNode(), value); } else { - auto value = desc.value; // For pinned curves, vertex interpolation primvars shouldn't be remapped if (_interpolation != HdTokens->linear && !(isPinned && desc.interpolation == HdInterpolationVertex)) { @@ -238,7 +249,7 @@ void HdArnoldBasisCurves::Sync( bool, VtUCharArray::value_type, unsigned int, int, float, GfVec2f, GfVec3f, GfVec4f, std::string, TfToken, SdfAssetPath>(value); } - HdArnoldSetVertexPrimvar(GetArnoldNode(), primvar.first, desc.role, value); + HdArnoldSetVertexPrimvar(GetArnoldNode(), arnoldAttributeName, desc.role, value); } } } diff --git a/testsuite/groups b/testsuite/groups index e8e74eb31c..087e3386c7 100755 --- a/testsuite/groups +++ b/testsuite/groups @@ -40,7 +40,7 @@ darwin: # SPECIAL TEST GROUPS # ####################### # Tests that can be run in hydra mode -hydra: test_0000 test_0001 test_0002 test_0003 test_0004 test_0005 test_0006 test_0007 test_0008 test_0009 test_0010 test_0011 test_0012 test_0014 test_0016 test_0017 test_0018 test_0019 test_0020 test_0021 test_0022 test_0023 test_0024 test_0025 test_0026 test_0027 test_0028 test_0029 test_0030 test_0031 test_0032 test_0033 test_0034 test_0038 test_0041 test_0046 test_0048 test_0049 test_0055 test_0112 test_0130 test_0132 test_0133 test_0135 test_0139 test_0140 test_0141 test_0142 test_0143 test_0144 test_0145 test_0148 test_0149 test_0150 test_0151 test_0158 test_0159 test_0161 test_0162 test_0163 test_0164 test_0165 test_0166 test_0168 test_0169 test_0170 test_0171 test_0172 test_0173 test_0174 test_0175 test_0177 test_0178 test_0180 test_0183 test_0184 test_0186 test_0187 test_0188 test_0189 test_0191 test_0194 test_0195 test_0196 test_0197 test_0198 test_0200 test_0201 test_0202 test_0204 test_0205 test_0206 test_0207 test_0215 test_0216 test_0217 test_0219 test_0220 test_0221 test_0222 test_0223 test_0225 test_0228 test_0229 test_0230 test_0299 test_0232 test_0233 test_0234 test_0238 test_0239 test_0240 test_0242 test_0243 test_0244 test_0245 test_0739 test_1181 test_1204 test_1209 test_1225 test_1245 test_1262 test_1294 test_1309 test_1311 test_1313 test_1333 test_1334 test_1416 test_1420 test_1426 test_1427.3 test_1433 test_1435 test_1438 test_1457 test_1486 test_1499 test_1524 test_1525 test_1530 test_1535 test_1538 test_1546 test_1550 test_1567 test_1588 test_1590 test_1593 test_1607 test_1613 test_1625 test_1632 test_1654 test_1657 test_1678 test_1718 test_1726 test_1735 +hydra: test_0000 test_0001 test_0002 test_0003 test_0004 test_0005 test_0006 test_0007 test_0008 test_0009 test_0010 test_0011 test_0012 test_0014 test_0016 test_0017 test_0018 test_0019 test_0020 test_0021 test_0022 test_0023 test_0024 test_0025 test_0026 test_0027 test_0028 test_0029 test_0030 test_0031 test_0032 test_0033 test_0034 test_0038 test_0041 test_0046 test_0048 test_0049 test_0055 test_0112 test_0130 test_0132 test_0133 test_0135 test_0139 test_0140 test_0141 test_0142 test_0143 test_0144 test_0145 test_0148 test_0149 test_0150 test_0151 test_0158 test_0159 test_0161 test_0162 test_0163 test_0164 test_0165 test_0166 test_0168 test_0169 test_0170 test_0171 test_0172 test_0173 test_0174 test_0175 test_0177 test_0178 test_0180 test_0183 test_0184 test_0186 test_0187 test_0188 test_0189 test_0191 test_0194 test_0195 test_0196 test_0197 test_0198 test_0200 test_0201 test_0202 test_0204 test_0205 test_0206 test_0207 test_0215 test_0216 test_0217 test_0219 test_0220 test_0221 test_0222 test_0223 test_0225 test_0228 test_0229 test_0230 test_0299 test_0232 test_0233 test_0234 test_0238 test_0239 test_0240 test_0242 test_0243 test_0244 test_0245 test_0739 test_1181 test_1204 test_1209 test_1225 test_1245 test_1262 test_1294 test_1309 test_1311 test_1313 test_1333 test_1334 test_1416 test_1420 test_1426 test_1427.3 test_1433 test_1435 test_1438 test_1457 test_1486 test_1499 test_1524 test_1525 test_1530 test_1535 test_1538 test_1546 test_1550 test_1567 test_1588 test_1590 test_1593 test_1607 test_1613 test_1625 test_1632 test_1654 test_1657 test_1678 test_1718 test_1726 test_1735 test_1769 # Tests in this group will never be executed (you can use it to temporarily disable some tests and/or groups) ignore: diff --git a/testsuite/test_1769/README b/testsuite/test_1769/README new file mode 100644 index 0000000000..c795276e6c --- /dev/null +++ b/testsuite/test_1769/README @@ -0,0 +1,7 @@ +BSpline curve with vertex interpolated uvs + +author: cyril.pichard@autodesk.com + +see #1769 + +PARAMS: {'scene':'test.usda'} diff --git a/testsuite/test_1769/data/test.usda b/testsuite/test_1769/data/test.usda new file mode 100644 index 0000000000..703483acda --- /dev/null +++ b/testsuite/test_1769/data/test.usda @@ -0,0 +1,83 @@ +#usda 1.0 +( + defaultPrim = "sopimport1" + endTimeCode = 1 + framesPerSecond = 24 + metersPerUnit = 1 + startTimeCode = 1 + timeCodesPerSecond = 24 + upAxis = "Y" +) + +def Xform "sopimport1" ( + kind = "component" +) +{ + def BasisCurves "curve_0" + { + uniform token basis = "bspline" + int[] curveVertexCounts = [9] + float3[] extent = [(0.6149099, 0, 1.2895236), (0.6149099, 0.799, 1.2895236)] + point3f[] points = [(0.6149099, 0, 1.2895236), (0.6149099, 0, 1.2895236), (0.6149099, 0, 1.2895236), (0.6149099, 0.19975, 1.2895236), (0.6149099, 0.3995, 1.2895236), (0.6149099, 0.59925, 1.2895236), (0.6149099, 0.799, 1.2895236), (0.6149099, 0.799, 1.2895236), (0.6149099, 0.799, 1.2895236)] ( + interpolation = "vertex" + ) + texCoord2f[] primvars:st = [(0.6537275, 0.8223809), (0.6537275, 0.8223809), (0.6537275, 0.8223809), (0.6537275, 0.8223809), (0.6537275, 0.8223809), (0.6537275, 0.8223809), (0.6537275, 0.8223809), (0.6537275, 0.8223809), (0.6537275, 0.8223809)] ( + interpolation = "vertex" + ) + int[] primvars:st:indices = None + uniform token type = "cubic" + uniform token wrap = "nonperiodic" + } +} + +def Xform "lights" +{ + def RectLight "arealight1" ( + prepend apiSchemas = ["HoudiniViewportLightAPI", "HoudiniViewportGuideAPI"] + ) + { + float2 houdini:clippingRange = (0.001, 10000) + bool houdini:inviewermenu = 1 + color3f inputs:color = (1, 1, 1) + float inputs:diffuse = 1 + bool inputs:enableColorTemperature = 0 + float inputs:exposure = 0 + float inputs:height = 7.448014 + float inputs:intensity = 0.1 + bool inputs:normalize = 0 + float inputs:specular = 1 + asset inputs:texture:file = @@ + float inputs:width = 8.364269 + rel light:filters = None + matrix4d xformOp:transform = ( (-0.02482371480219213, -0.9990594771725642, 0.03555199368674425, 0), (-1.8395864258974326e-12, -0.035562952619954354, -0.9993674381332178, 0), (0.999691844111684, -0.024808012266881785, 0.0008828045915237619, 0), (1.5704420804977417, 0.43900111317634605, 1.7137359082698838, 1) ) + uniform token[] xformOpOrder = ["xformOp:transform"] + } +} + +def Xform "cameras" +{ + def Camera "camera1" ( + prepend apiSchemas = ["HoudiniCameraPlateAPI", "HoudiniViewportGuideAPI"] + ) + { + float2 clippingRange = (1, 1000000) + float exposure = 0 + float focalLength = 0.45 + float focusDistance = 10.78378 + float fStop = 0 + float horizontalAperture = 0.20955 + float horizontalApertureOffset = 0 + asset houdini:backgroundimage = @@ + asset houdini:foregroundimage = @@ + float houdini:guidescale = 1 + bool houdini:inviewermenu = 1 + token projection = "perspective" + double shutter:close = 0.25 + double shutter:open = -0.25 + float verticalAperture = 0.11787187 + float verticalApertureOffset = 0 + matrix4d xformOp:transform = ( (0.5250461978776859, -0.0007888840709954176, -0.8510733621469471, 0), (-0.036986569010682126, 0.999033644144815, -0.023743874569022813, 0), (0.8502696535846755, 0.04394491470755142, 0.5245096382949908, 0), (3.7343048332866244, 0.550095433860866, 3.2061258043688006, 1) ) + uniform token[] xformOpOrder = ["xformOp:transform"] + } +} + diff --git a/testsuite/test_1769/ref/reference.tif b/testsuite/test_1769/ref/reference.tif new file mode 100644 index 0000000000000000000000000000000000000000..748f601747f79b281235598a8d3a0aad00b4668e GIT binary patch literal 4101 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