Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support "vertex" UV coordinates on curves in the render delegate #1578

Merged
merged 4 commits into from
Jul 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Feature
- [usd#1435](https://github.com/Autodesk/arnold-usd/issues/1435) - Support "vertex" UV coordinates on Curves in the render delegate
- [usd#1579](https://github.com/Autodesk/arnold-usd/issues/1579) - Curves without any width should render with a default value

### Bug fixes
- [usd#1567](https://github.com/Autodesk/arnold-usd/issues/1567) - Fix metallic attribute in UsdPreviewSurface in the render delegate
- [usd#1550](https://github.com/Autodesk/arnold-usd/issues/1550) - UsdPrimvarReader_float2 returning "st" not working in the usd procedural
Expand Down
57 changes: 28 additions & 29 deletions libs/render_delegate/basis_curves.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,33 @@ void HdArnoldBasisCurves::Sync(
} else {
ArnoldUsdCurvesData::SetRadiusFromValue(GetArnoldNode(), desc.value);
}
// For constant and
} else if (desc.interpolation == HdInterpolationConstant) {
continue;
}
if (primvar.first == str::t_uv || primvar.first == str::t_st) {
// This is either a VtVec2fArray or VtVec3fArray (in Solaris).
if (desc.value.IsHolding<VtVec2fArray>()) {
const auto& v = desc.value.UncheckedGet<VtVec2fArray>();
AiNodeSetArray(
GetArnoldNode(), str::uvs, AiArrayConvert(v.size(), 1, AI_TYPE_VECTOR2, v.data()));
continue;
}
if (desc.value.IsHolding<VtVec3fArray>()) {
const auto& v = desc.value.UncheckedGet<VtVec3fArray>();
auto* arr = AiArrayAllocate(v.size(), 1, AI_TYPE_VECTOR2);
if (!v.empty()) {
std::transform(
v.begin(), v.end(), static_cast<GfVec2f*>(AiArrayMap(arr)),
[](const GfVec3f& in) -> GfVec2f {
return {in[0], in[1]};
});
AiArrayUnmap(arr);
}
AiNodeSetArray(GetArnoldNode(), str::uvs, arr);
continue;
}
}

if (desc.interpolation == HdInterpolationConstant) {
// We skip reading the basis for now as it would require remapping the vertices, widths and
// all the primvars.
if (primvar.first != _tokens->basis) {
Expand All @@ -191,31 +216,7 @@ void HdArnoldBasisCurves::Sync(
nullptr);
}
} else if (desc.interpolation == HdInterpolationUniform) {
if (primvar.first == str::t_uv || primvar.first == str::t_st) {
// This is either a VtVec2fArray or VtVec3fArray (in Solaris).
if (desc.value.IsHolding<VtVec2fArray>()) {
const auto& v = desc.value.UncheckedGet<VtVec2fArray>();
AiNodeSetArray(
GetArnoldNode(), str::uvs, AiArrayConvert(v.size(), 1, AI_TYPE_VECTOR2, v.data()));
} else if (desc.value.IsHolding<VtVec3fArray>()) {
const auto& v = desc.value.UncheckedGet<VtVec3fArray>();
auto* arr = AiArrayAllocate(v.size(), 1, AI_TYPE_VECTOR2);
if (!v.empty()) {
std::transform(
v.begin(), v.end(), static_cast<GfVec2f*>(AiArrayMap(arr)),
[](const GfVec3f& in) -> GfVec2f {
return {in[0], in[1]};
});
AiArrayUnmap(arr);
}
AiNodeSetArray(GetArnoldNode(), str::uvs, arr);
} else {
// If it's an unsupported type, just set it as user data.
HdArnoldSetUniformPrimvar(GetArnoldNode(), primvar.first, desc.role, desc.value);
}
} else {
HdArnoldSetUniformPrimvar(GetArnoldNode(), primvar.first, desc.role, desc.value);
}
HdArnoldSetUniformPrimvar(GetArnoldNode(), primvar.first, desc.role, desc.value);
} else if (desc.interpolation == HdInterpolationVertex || desc.interpolation == HdInterpolationVarying) {
if (primvar.first == HdTokens->points) {
HdArnoldSetPositionFromValue(GetArnoldNode(), str::curves, desc.value);
Expand All @@ -233,8 +234,6 @@ void HdArnoldBasisCurves::Sync(
}
HdArnoldSetVertexPrimvar(GetArnoldNode(), primvar.first, desc.role, value);
}
} else if (desc.interpolation == HdInterpolationVarying) {
HdArnoldSetVertexPrimvar(GetArnoldNode(), primvar.first, desc.role, desc.value);
}
}
UpdateVisibilityAndSidedness();
Expand Down
15 changes: 7 additions & 8 deletions libs/render_delegate/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1729,17 +1729,16 @@ AtArray* HdArnoldGetShidxs(const HdGeomSubsets& subsets, int numFaces, HdArnoldS

bool HdArnoldDeclare(AtNode* node, const TfToken& name, const TfToken& scope, const TfToken& type)
{
if (AiNodeEntryLookUpParameter(AiNodeGetNodeEntry(node), AtString(name.GetText())) != nullptr) {
TF_DEBUG(HDARNOLD_PRIMVARS)
.Msg(
"Unable to translate %s primvar for %s due to a name collision with a built-in parameter",
name.GetText(), AiNodeGetName(node));
return false;
}
const AtString nameStr{name.GetText()};
if (AiNodeLookUpUserParameter(node, nameStr) != nullptr) {
// If the attribute already exists (either as a node entry parameter
// or as a user data in the node), then we should not call AiNodeDeclare
// as it would fail.
if (AiNodeLookUpUserParameter(node, nameStr) ||
AiNodeEntryLookUpParameter(AiNodeGetNodeEntry(node), nameStr)) {
AiNodeResetParameter(node, nameStr);
return true;
}

return AiNodeDeclare(node, nameStr, AtString(TfStringPrintf("%s %s", scope.GetText(), type.GetText()).c_str()));
}

Expand Down
34 changes: 16 additions & 18 deletions libs/translator/reader/read_geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -480,13 +480,7 @@ void UsdArnoldReadCurves::Read(const UsdPrim &prim, UsdArnoldReaderContext &cont
staticTime.motionBlur = false;

UsdGeomCurves curves(prim);

VtValue widthValues;
if (!curves.GetWidthsAttr().Get(&widthValues, frame)) {
AiMsgWarning("[usd] Skipping curves with empty width %s", prim.GetPath().GetText());
return;
}


AtNode *node = context.CreateArnoldNode("curves", prim.GetPath().GetText());

AtString basis = str::linear;
Expand Down Expand Up @@ -516,8 +510,6 @@ void UsdArnoldReadCurves::Read(const UsdPrim &prim, UsdArnoldReaderContext &cont
}
}



AiNodeSetStr(node, str::basis, basis);

// CV counts per curve
Expand All @@ -533,16 +525,22 @@ void UsdArnoldReadCurves::Read(const UsdPrim &prim, UsdArnoldReaderContext &cont
const auto vstep = basis == str::bezier ? 3 : 1;
const auto vmin = basis == str::linear ? 2 : 4;
ArnoldUsdCurvesData curvesData(vmin, vstep, vertexCounts);

TfToken widthInterpolation = curves.GetWidthsInterpolation();
if ((widthInterpolation == UsdGeomTokens->vertex || widthInterpolation == UsdGeomTokens->varying) &&
basis != str::linear) {
// if radius data is per-vertex and the curve is pinned, then don't remap
if (!(widthInterpolation == UsdGeomTokens->vertex && isValidPinnedCurve))
curvesData.RemapCurvesVertexPrimvar<float, double>(widthValues);
curvesData.SetRadiusFromValue(node, widthValues);

VtValue widthValues;
if (curves.GetWidthsAttr().Get(&widthValues, frame)) {
TfToken widthInterpolation = curves.GetWidthsInterpolation();
if ((widthInterpolation == UsdGeomTokens->vertex || widthInterpolation == UsdGeomTokens->varying) &&
basis != str::linear) {
// if radius data is per-vertex and the curve is pinned, then don't remap
if (!(widthInterpolation == UsdGeomTokens->vertex && isValidPinnedCurve))
curvesData.RemapCurvesVertexPrimvar<float, double>(widthValues);
curvesData.SetRadiusFromValue(node, widthValues);
} else {
curvesData.SetRadiusFromValue(node, widthValues);
}
} else {
curvesData.SetRadiusFromValue(node, widthValues);
// Width isn't defined, we assume a constant width equal to 1
AiNodeSetFlt(node, str::radius, 0.5);
}

ReadMatrix(prim, node, time, context);
Expand Down
7 changes: 7 additions & 0 deletions testsuite/test_1435/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Curves with per-vertex st coordinates

See #1435

author: sebastien.ortega

PARAMS: {'scene':'test.usda'}
211 changes: 211 additions & 0 deletions testsuite/test_1435/data/test.usda
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
#usda 1.0
(
doc = """Generated from Composed Stage of root layer
"""
endTimeCode = 1
framesPerSecond = 24
metersPerUnit = 1
startTimeCode = 1
timeCodesPerSecond = 24
upAxis = "Y"
)

def Xform "test" (
kind = "component"
)
{
def BasisCurves "test" (
apiSchemas = ["MaterialBindingAPI"]
)
{
uniform token basis = "bezier"
int[] curveVertexCounts = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
float3[] extent = [(-5, 0, -5), (5, 1, 3.5779235)]
rel material:binding = </materials/shader>
point3f[] points = [(-0.86734253, 0, -0.9439319), (-0.86734253, 1, -0.9439319), (5, 0, 0.7396351), (5, 1, 0.7396351), (-2.928457, 0, -2.2366061), (-2.928457, 1, -2.2366061), (-0.9475007, 0, -3.191457), (-0.9475007, 1, -3.191457), (2.1079116, 0, 1.7289146), (2.1079116, 1, 1.7289146), (-3.0919335, 0, 0.07936842), (-3.0919335, 1, 0.07936842), (-5, 0, 1.499233), (-5, 1, 1.499233), (1.4457333, 0, -0.7533004), (1.4457333, 1, -0.7533004), (0.2606192, 0, 0.9491923), (0.2606192, 1, 0.9491923), (1.1564449, 0, -2.8530495), (1.1564449, 1, -2.8530495), (5, 0, -2.212023), (5, 1, -2.212023), (-1.3227377, 0, 2.1443152), (-1.3227377, 1, 2.1443152), (-4.9845285, 0, -1.2268404), (-4.9845285, 1, -1.2268404), (-3.2350502, 0, 3.0137196), (-3.2350502, 1, 3.0137196), (3.179194, 0, -1.9110526), (3.179194, 1, -1.9110526), (3.4112368, 0, 0.16663373), (3.4112368, 1, 0.16663373), (-4.0955606, 0, -4.076156), (-4.0955606, 1, -4.076156), (3.3390605, 0, -4.132369), (3.3390605, 1, -4.132369), (3.6978378, 0, 3.1946297), (3.6978378, 1, 3.1946297), (0.96328783, 0, -5), (0.96328783, 1, -5), (-1.6550982, 0, -5), (-1.6550982, 1, -5), (0.8823204, 0, 3.5779235), (0.8823204, 1, 3.5779235)] (
interpolation = "vertex"
)
string primvars:arnold:mode = "thick" (
interpolation = "constant"
)
texCoord2f[] primvars:st = [(0.41326576, 0.4056068), (0.41326576, 0.4056068), (1, 0.5739635), (1, 0.5739635), (0.2071543, 0.27633938), (0.2071543, 0.27633938), (0.40524995, 0.18085429), (0.40524995, 0.18085429), (0.7107911, 0.67289144), (0.7107911, 0.67289144), (0.19080666, 0.50793684), (0.19080666, 0.50793684), (0, 0.6499233), (0, 0.6499233), (0.6445733, 0.42466995), (0.6445733, 0.42466995), (0.5260619, 0.5949192), (0.5260619, 0.5949192), (0.61564445, 0.21469504), (0.61564445, 0.21469504), (1, 0.2787977), (1, 0.2787977), (0.36772624, 0.7144315), (0.36772624, 0.7144315), (0.0015471459, 0.37731594), (0.0015471459, 0.37731594), (0.17649497, 0.801372), (0.17649497, 0.801372), (0.81791943, 0.30889475), (0.81791943, 0.30889475), (0.84112364, 0.5166634), (0.84112364, 0.5166634), (0.09044395, 0.09238439), (0.09044395, 0.09238439), (0.83390605, 0.0867631), (0.83390605, 0.0867631), (0.8697838, 0.819463), (0.8697838, 0.819463), (0.5963288, 0), (0.5963288, 0), (0.33449015, 0), (0.33449015, 0), (0.58823204, 0.8577924), (0.58823204, 0.8577924)] (
interpolation = "vertex"
)
int[] primvars:st:indices = None
uniform token type = "linear"
uniform token wrap = "nonperiodic"
}
}

def Scope "materials"
{
def Material "shader"
{
token outputs:arnold:surface.connect = </materials/shader/standard_surface1.outputs:shader>

def Shader "standard_surface1"
{
uniform token info:id = "arnold:standard_surface"
string inputs:aov_id1 = ""
string inputs:aov_id2 = ""
string inputs:aov_id3 = ""
string inputs:aov_id4 = ""
string inputs:aov_id5 = ""
string inputs:aov_id6 = ""
string inputs:aov_id7 = ""
string inputs:aov_id8 = ""
float inputs:base = 1
color3f inputs:base_color = (0.8, 0.8, 0.8)
color3f inputs:base_color.connect = </materials/shader/checkerboard_good.outputs:rgb>
bool inputs:caustics = 0
float inputs:coat = 0
float inputs:coat_affect_color = 0
float inputs:coat_affect_roughness = 0
float inputs:coat_anisotropy = 0
color3f inputs:coat_color = (1, 1, 1)
float inputs:coat_IOR = 1.5
vector3f inputs:coat_normal = (0, 0, 0)
float inputs:coat_rotation = 0
float inputs:coat_roughness = 0.1
int inputs:dielectric_priority = 0
float inputs:diffuse_roughness = 0
float inputs:emission = 0
color3f inputs:emission_color = (1, 1, 1)
bool inputs:exit_to_background = 0
color3f inputs:id1 = (0, 0, 0)
color3f inputs:id2 = (0, 0, 0)
color3f inputs:id3 = (0, 0, 0)
color3f inputs:id4 = (0, 0, 0)
color3f inputs:id5 = (0, 0, 0)
color3f inputs:id6 = (0, 0, 0)
color3f inputs:id7 = (0, 0, 0)
color3f inputs:id8 = (0, 0, 0)
float inputs:indirect_diffuse = 1
float inputs:indirect_specular = 1
bool inputs:internal_reflections = 1
float inputs:metalness = 0
vector3f inputs:normal = (0, 0, 0)
color3f inputs:opacity = (1, 1, 1)
float inputs:sheen = 0
color3f inputs:sheen_color = (1, 1, 1)
float inputs:sheen_roughness = 0.3
float inputs:specular = 1
float inputs:specular_anisotropy = 0
color3f inputs:specular_color = (1, 1, 1)
float inputs:specular_IOR = 1.5
float inputs:specular_rotation = 0
float inputs:specular_roughness = 0.2
float inputs:subsurface = 0
float inputs:subsurface_anisotropy = 0
color3f inputs:subsurface_color = (1, 1, 1)
color3f inputs:subsurface_radius = (1, 1, 1)
float inputs:subsurface_scale = 1
token inputs:subsurface_type = "randomwalk"
vector3f inputs:tangent = (0, 0, 0)
float inputs:thin_film_IOR = 1.5
float inputs:thin_film_thickness = 0
bool inputs:thin_walled = 0
float inputs:transmission = 0
color3f inputs:transmission_color = (1, 1, 1)
float inputs:transmission_depth = 0
float inputs:transmission_dispersion = 0
float inputs:transmission_extra_roughness = 0
color3f inputs:transmission_scatter = (0, 0, 0)
float inputs:transmission_scatter_anisotropy = 0
bool inputs:transmit_aovs = 0
token outputs:shader
}

def Shader "checkerboard_good"
{
uniform token info:id = "arnold:checkerboard"
color3f inputs:color1 = (1, 1, 1)
color3f inputs:color2 = (0, 0, 0)
float inputs:contrast = 1
float inputs:filter_offset = 0
float inputs:filter_strength = 1
float inputs:u_frequency = 1
float inputs:u_offset = 0
string inputs:uvset = ""
float inputs:v_frequency = 1.27
float inputs:v_offset = 0
color3f outputs:rgb
}
}
}

def Xform "lights"
{
def DomeLight "domelight1" (
apiSchemas = ["HoudiniViewportGuideAPI"]
)
{
custom rel filters
float houdini:guidescale = 1
uniform bool houdini:inviewermenu = 0
color3f inputs:color = (1, 1, 1)
float inputs:diffuse = 1
bool inputs:enableColorTemperature = 0
float inputs:exposure = 0
float inputs:intensity = 1
bool inputs:normalize = 0
float inputs:specular = 1
asset inputs:texture:file = @@
token inputs:texture:format = "automatic"
rel light:filters
rel portals
float primvars:arnold:camera = 0 (
interpolation = "constant"
)
matrix4d xformOp:transform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) )
uniform token[] xformOpOrder = ["xformOp:transform"]
}
}

def Xform "cameras"
{
def Camera "camera1" (
apiSchemas = ["HoudiniCameraPlateAPI", "HoudiniViewportGuideAPI"]
)
{
float2 clippingRange = (1, 1000000)
float exposure = 0
float focalLength = 0.5
float focusDistance = 5
float fStop = 0
float horizontalAperture = 0.20955
float horizontalApertureOffset = 0
asset houdini:backgroundimage = @@
asset houdini:foregroundimage = @@
float houdini:guidescale = 1
uniform 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.9995288042127394, 0, -0.03069478048547104, 0), (-0.004382454461563712, 0.9897551376987948, -0.14270795875399597, 0), (0.030380316686031666, 0.1427752338427078, 0.9892887692474915, 0), (-1.5657610058776417, 2.6599768452283414, 15.047198989242691, 1) )
uniform token[] xformOpOrder = ["xformOp:transform"]
}
}

def Scope "Render"
{
def RenderSettings "rendersettings"
{
custom int arnold:global:AA_seed
int arnold:global:AA_seed.timeSamples = {
1: 1,
}
uniform token aspectRatioConformPolicy = "expandAperture"
rel camera = </cameras/camera1>
uniform float4 dataWindowNDC = (0, 0, 1, 1)
uniform token[] includedPurposes = ["default"]
uniform bool instantaneousShutter = 0
uniform token[] materialBindingPurposes = ["full", "allPurpose"]
uniform float pixelAspectRatio = 1
rel products
uniform int2 resolution = (2048, 1152)
}
}

Loading