Skip to content

Commit d999875

Browse files
authored
Merge branch 'AcademySoftwareFoundation:main' into functional_nodedefs
2 parents 6fc3a7b + 32bdd68 commit d999875

8 files changed

Lines changed: 156 additions & 181 deletions

File tree

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ jobs:
8585
compiler_version: "26.0"
8686
python: 3.13
8787
static_analysis: ON
88-
cmake_config: -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
88+
cmake_config: -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DMATERIALX_BUILD_DATA_LIBRARY=ON
8989

9090
- name: MacOS_Xcode_DynamicAnalysis
9191
os: macos-26

libraries/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ if(MATERIALX_BUILD_DATA_LIBRARY)
1313
*.glsl
1414
*.osl
1515
*.h
16-
*.metal)
16+
*.metal
17+
*.slang)
1718

1819
foreach(SOURCE_FILE IN LISTS MATERIALX_DATA_LIBRARY_SOURCE_FILES)
1920
set(SOURCE_FILEPATH ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_FILE})

libraries/stdlib/genglsl/lib/mx_hextile.glsl

Lines changed: 42 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,29 @@ float mx_schlick_gain(float x, float r)
1818

1919
struct HextileData
2020
{
21-
vec2 coord1;
22-
vec2 coord2;
23-
vec2 coord3;
21+
vec2 coords[3];
2422
vec3 weights;
25-
float rot_radian1;
26-
float rot_radian2;
27-
float rot_radian3;
28-
vec2 ddx1;
29-
vec2 ddx2;
30-
vec2 ddx3;
31-
vec2 ddy1;
32-
vec2 ddy2;
33-
vec2 ddy3;
23+
vec3 rotations;
24+
vec2 ddx[3];
25+
vec2 ddy[3];
3426
};
3527

28+
// Helper function to compute blend weights with optional falloff
29+
vec3 mx_hextile_compute_blend_weights(vec3 luminance_weights, vec3 tile_weights, float falloff)
30+
{
31+
vec3 w = luminance_weights * pow(tile_weights, vec3(7.0));
32+
w /= (w.x + w.y + w.z);
33+
34+
if (falloff != 0.5)
35+
{
36+
w.x = mx_schlick_gain(w.x, falloff);
37+
w.y = mx_schlick_gain(w.y, falloff);
38+
w.z = mx_schlick_gain(w.z, falloff);
39+
w /= (w.x + w.y + w.z);
40+
}
41+
return w;
42+
}
43+
3644
// Morten S. Mikkelsen, Practical Real-Time Hex-Tiling, Journal of Computer Graphics
3745
// Techniques (JCGT), vol. 11, no. 2, 77-94, 2022
3846
// http://jcgt.org/published/0011/03/05/
@@ -88,24 +96,20 @@ HextileData mx_hextile_coord(
8896

8997
// randomized rotation matrix
9098
vec2 rr = mx_radians(rotation_range);
91-
float rv1 = mix(rr.x, rr.y, rand1.x * rotation);
92-
float rv2 = mix(rr.x, rr.y, rand2.x * rotation);
93-
float rv3 = mix(rr.x, rr.y, rand3.x * rotation);
94-
float sin_r1 = sin(rv1);
95-
float sin_r2 = sin(rv2);
96-
float sin_r3 = sin(rv3);
97-
float cos_r1 = cos(rv1);
98-
float cos_r2 = cos(rv2);
99-
float cos_r3 = cos(rv3);
100-
mat2 rm1 = mat2(cos_r1, -sin_r1, sin_r1, cos_r1);
101-
mat2 rm2 = mat2(cos_r2, -sin_r2, sin_r2, cos_r2);
102-
mat2 rm3 = mat2(cos_r3, -sin_r3, sin_r3, cos_r3);
99+
vec3 rand_x = vec3(rand1.x, rand2.x, rand3.x);
100+
vec3 rotations = mix(vec3(rr.x), vec3(rr.y), rand_x * rotation);
101+
vec3 sin_r = sin(rotations);
102+
vec3 cos_r = cos(rotations);
103+
mat2 rm1 = mat2(cos_r.x, -sin_r.x, sin_r.x, cos_r.x);
104+
mat2 rm2 = mat2(cos_r.y, -sin_r.y, sin_r.y, cos_r.y);
105+
mat2 rm3 = mat2(cos_r.z, -sin_r.z, sin_r.z, cos_r.z);
103106

104107
// randomized scale
105-
vec2 sr = scale_range;
106-
vec2 scale1 = vec2(mix(1.0, mix(sr.x, sr.y, rand1.y), scale));
107-
vec2 scale2 = vec2(mix(1.0, mix(sr.x, sr.y, rand2.y), scale));
108-
vec2 scale3 = vec2(mix(1.0, mix(sr.x, sr.y, rand3.y), scale));
108+
vec3 rand_y = vec3(rand1.y, rand2.y, rand3.y);
109+
vec3 scales = mix(vec3(1.0), mix(vec3(scale_range.x), vec3(scale_range.y), rand_y), scale);
110+
vec2 scale1 = vec2(scales.x);
111+
vec2 scale2 = vec2(scales.y);
112+
vec2 scale3 = vec2(scales.z);
109113

110114
// randomized offset
111115
vec2 offset1 = mix(vec2(offset_range.x), vec2(offset_range.y), rand1 * offset);
@@ -114,24 +118,22 @@ HextileData mx_hextile_coord(
114118

115119
HextileData tile_data;
116120
tile_data.weights = vec3(w1, w2, w3);
117-
tile_data.rot_radian1 = rv1;
118-
tile_data.rot_radian2 = rv2;
119-
tile_data.rot_radian3 = rv3;
121+
tile_data.rotations = rotations;
120122

121123
// get coord
122-
tile_data.coord1 = (mx_matrix_mul((coord - ctr1), rm1) / scale1) + ctr1 + offset1;
123-
tile_data.coord2 = (mx_matrix_mul((coord - ctr2), rm2) / scale2) + ctr2 + offset2;
124-
tile_data.coord3 = (mx_matrix_mul((coord - ctr3), rm3) / scale3) + ctr3 + offset3;
124+
tile_data.coords[0] = (mx_matrix_mul((coord - ctr1), rm1) / scale1) + ctr1 + offset1;
125+
tile_data.coords[1] = (mx_matrix_mul((coord - ctr2), rm2) / scale2) + ctr2 + offset2;
126+
tile_data.coords[2] = (mx_matrix_mul((coord - ctr3), rm3) / scale3) + ctr3 + offset3;
125127

126128
// derivatives
127129
vec2 ddx = dFdx(coord);
128130
vec2 ddy = dFdy(coord);
129-
tile_data.ddx1 = mx_matrix_mul(ddx, rm1) / scale1;
130-
tile_data.ddx2 = mx_matrix_mul(ddx, rm2) / scale2;
131-
tile_data.ddx3 = mx_matrix_mul(ddx, rm3) / scale3;
132-
tile_data.ddy1 = mx_matrix_mul(ddy, rm1) / scale1;
133-
tile_data.ddy2 = mx_matrix_mul(ddy, rm2) / scale2;
134-
tile_data.ddy3 = mx_matrix_mul(ddy, rm3) / scale3;
131+
tile_data.ddx[0] = mx_matrix_mul(ddx, rm1) / scale1;
132+
tile_data.ddx[1] = mx_matrix_mul(ddx, rm2) / scale2;
133+
tile_data.ddx[2] = mx_matrix_mul(ddx, rm3) / scale3;
134+
tile_data.ddy[0] = mx_matrix_mul(ddy, rm1) / scale1;
135+
tile_data.ddy[1] = mx_matrix_mul(ddy, rm2) / scale2;
136+
tile_data.ddy[2] = mx_matrix_mul(ddy, rm3) / scale3;
135137

136138
return tile_data;
137139
}

libraries/stdlib/genglsl/mx_hextiledimage.glsl

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,18 @@ void mx_hextiledimage_color3(
2525

2626
HextileData tile_data = mx_hextile_coord(coord, rotation, rotation_range, scale, scale_range, offset, offset_range);
2727

28-
vec3 c1 = textureGrad($texSamplerSampler2D, tile_data.coord1, tile_data.ddx1, tile_data.ddy1).rgb;
29-
vec3 c2 = textureGrad($texSamplerSampler2D, tile_data.coord2, tile_data.ddx2, tile_data.ddy2).rgb;
30-
vec3 c3 = textureGrad($texSamplerSampler2D, tile_data.coord3, tile_data.ddx3, tile_data.ddy3).rgb;
28+
vec3 c1 = textureGrad($texSamplerSampler2D, tile_data.coords[0], tile_data.ddx[0], tile_data.ddy[0]).rgb;
29+
vec3 c2 = textureGrad($texSamplerSampler2D, tile_data.coords[1], tile_data.ddx[1], tile_data.ddy[1]).rgb;
30+
vec3 c3 = textureGrad($texSamplerSampler2D, tile_data.coords[2], tile_data.ddx[2], tile_data.ddy[2]).rgb;
3131

3232
// luminance as weights
3333
vec3 cw = vec3(dot(c1, lumacoeffs), dot(c2, lumacoeffs), dot(c3, lumacoeffs));
3434
cw = mix(vec3(1.0), cw, vec3(falloff_contrast));
3535

36-
// blend weights
37-
vec3 w = cw * pow(tile_data.weights, vec3(7.0));
38-
w /= (w.x + w.y + w.z);
39-
40-
// apply s-curve gain
41-
if (falloff != 0.5)
42-
{
43-
w.x = mx_schlick_gain(w.x, falloff);
44-
w.y = mx_schlick_gain(w.y, falloff);
45-
w.z = mx_schlick_gain(w.z, falloff);
46-
w /= (w.x + w.y + w.z);
47-
}
36+
vec3 w = mx_hextile_compute_blend_weights(cw, tile_data.weights, falloff);
4837

4938
// blend
50-
result = vec3(w.x * c1 + w.y * c2 + w.z * c3);
39+
result = w.x * c1 + w.y * c2 + w.z * c3;
5140
}
5241

5342
void mx_hextiledimage_color4(
@@ -71,32 +60,24 @@ void mx_hextiledimage_color4(
7160

7261
HextileData tile_data = mx_hextile_coord(coord, rotation, rotation_range, scale, scale_range, offset, offset_range);
7362

74-
vec4 c1 = textureGrad($texSamplerSampler2D, tile_data.coord1, tile_data.ddx1, tile_data.ddy1);
75-
vec4 c2 = textureGrad($texSamplerSampler2D, tile_data.coord2, tile_data.ddx2, tile_data.ddy2);
76-
vec4 c3 = textureGrad($texSamplerSampler2D, tile_data.coord3, tile_data.ddx3, tile_data.ddy3);
63+
vec4 c1 = textureGrad($texSamplerSampler2D, tile_data.coords[0], tile_data.ddx[0], tile_data.ddy[0]);
64+
vec4 c2 = textureGrad($texSamplerSampler2D, tile_data.coords[1], tile_data.ddx[1], tile_data.ddy[1]);
65+
vec4 c3 = textureGrad($texSamplerSampler2D, tile_data.coords[2], tile_data.ddx[2], tile_data.ddy[2]);
7766

7867
// luminance as weights
7968
vec3 cw = vec3(dot(c1.rgb, lumacoeffs), dot(c2.rgb, lumacoeffs), dot(c3.rgb, lumacoeffs));
8069
cw = mix(vec3(1.0), cw, vec3(falloff_contrast));
8170

82-
// blend weights
83-
vec3 w = cw * pow(tile_data.weights, vec3(7.0));
84-
w /= (w.x + w.y + w.z);
71+
vec3 w = mx_hextile_compute_blend_weights(cw, tile_data.weights, falloff);
8572

8673
// alpha
8774
float a = (c1.a + c2.a + c3.a) / 3.0;
88-
89-
// apply s-curve gain
9075
if (falloff != 0.5)
9176
{
92-
w.x = mx_schlick_gain(w.x, falloff);
93-
w.y = mx_schlick_gain(w.y, falloff);
94-
w.z = mx_schlick_gain(w.z, falloff);
95-
w /= (w.x + w.y + w.z);
9677
a = mx_schlick_gain(a, falloff);
9778
}
9879

9980
// blend
100-
result.rgb = (w.x * c1 + w.y * c2 + w.z * c3).rgb;
81+
result.rgb = w.x * c1.rgb + w.y * c2.rgb + w.z * c3.rgb;
10182
result.a = a;
10283
}

libraries/stdlib/genglsl/mx_hextilednormalmap.glsl

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ void mx_hextilednormalmap_vector3(
2929

3030
HextileData tile_data = mx_hextile_coord(coord, rotation, rotation_range, scale, scale_range, offset, offset_range);
3131

32-
vec3 nm1 = textureGrad($texSamplerSampler2D, tile_data.coord1, tile_data.ddx1, tile_data.ddy1).xyz;
33-
vec3 nm2 = textureGrad($texSamplerSampler2D, tile_data.coord2, tile_data.ddx2, tile_data.ddy2).xyz;
34-
vec3 nm3 = textureGrad($texSamplerSampler2D, tile_data.coord3, tile_data.ddx3, tile_data.ddy3).xyz;
32+
vec3 nm1 = textureGrad($texSamplerSampler2D, tile_data.coords[0], tile_data.ddx[0], tile_data.ddy[0]).xyz;
33+
vec3 nm2 = textureGrad($texSamplerSampler2D, tile_data.coords[1], tile_data.ddx[1], tile_data.ddy[1]).xyz;
34+
vec3 nm3 = textureGrad($texSamplerSampler2D, tile_data.coords[2], tile_data.ddx[2], tile_data.ddy[2]).xyz;
3535

3636
nm1.y = flip_g ? 1.0 - nm1.y : nm1.y;
3737
nm2.y = flip_g ? 1.0 - nm2.y : nm2.y;
@@ -41,9 +41,9 @@ void mx_hextilednormalmap_vector3(
4141
nm1 = 2.0 * nm1 - 1.0;
4242
nm2 = 2.0 * nm2 - 1.0;
4343
nm3 = 2.0 * nm3 - 1.0;
44-
mat3 tangent_rot_mat1 = mx_axis_rotation_matrix(N, -tile_data.rot_radian1);
45-
mat3 tangent_rot_mat2 = mx_axis_rotation_matrix(N, -tile_data.rot_radian2);
46-
mat3 tangent_rot_mat3 = mx_axis_rotation_matrix(N, -tile_data.rot_radian3);
44+
mat3 tangent_rot_mat1 = mx_axis_rotation_matrix(N, -tile_data.rotations.x);
45+
mat3 tangent_rot_mat2 = mx_axis_rotation_matrix(N, -tile_data.rotations.y);
46+
mat3 tangent_rot_mat3 = mx_axis_rotation_matrix(N, -tile_data.rotations.z);
4747
vec3 T1 = mx_matrix_mul(tangent_rot_mat1, T) * strength;
4848
vec3 T2 = mx_matrix_mul(tangent_rot_mat2, T) * strength;
4949
vec3 T3 = mx_matrix_mul(tangent_rot_mat3, T) * strength;
@@ -55,17 +55,7 @@ void mx_hextilednormalmap_vector3(
5555
vec3 N3 = normalize(T3 * nm3.x + B3 * nm3.y + N * nm3.z);
5656

5757
// blend weights
58-
vec3 w = pow(tile_data.weights, vec3(7.0));
59-
w /= (w.x + w.y + w.z);
60-
61-
// apply s-curve gain
62-
if (falloff != 0.5)
63-
{
64-
w.x = mx_schlick_gain(w.x, falloff);
65-
w.y = mx_schlick_gain(w.y, falloff);
66-
w.z = mx_schlick_gain(w.z, falloff);
67-
w /= (w.x + w.y + w.z);
68-
}
58+
vec3 w = mx_hextile_compute_blend_weights(vec3(1.0), tile_data.weights, falloff);
6959

7060
// blend
7161
result = mx_gradient_blend_3_normals(N, N1, w.x, N2, w.y, N3, w.z);

source/MaterialXCore/Version.cpp

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,36 +1166,60 @@ void Document::upgradeVersion()
11661166
else if (nodeCategory == "swizzle")
11671167
{
11681168
InputPtr inInput = node->getInput("in");
1169-
InputPtr channelsInput = node->getInput("channels");
1170-
if (inInput &&
1171-
CHANNEL_COUNT_MAP.count(inInput->getType()) &&
1169+
const string sourceType = inInput ? inInput->getType() : "float";
1170+
if (CHANNEL_COUNT_MAP.count(sourceType) &&
11721171
CHANNEL_COUNT_MAP.count(node->getType()))
11731172
{
1173+
InputPtr channelsInput = node->getInput("channels");
11741174
string channelString = channelsInput ? channelsInput->getValueString() : EMPTY_STRING;
1175-
string sourceType = inInput->getType();
11761175
string destType = node->getType();
11771176
size_t sourceChannelCount = CHANNEL_COUNT_MAP.at(sourceType);
11781177
size_t destChannelCount = CHANNEL_COUNT_MAP.at(destType);
11791178

11801179
// Resolve the invalid case of having both a connection and a value
11811180
// by removing the value attribute.
1182-
if (inInput->hasValue())
1181+
if (inInput && inInput->hasValue())
11831182
{
11841183
if (inInput->hasNodeName() || inInput->hasNodeGraphString() || inInput->hasInterfaceName())
11851184
{
11861185
inInput->removeAttribute(ValueElement::VALUE_ATTRIBUTE);
11871186
}
11881187
}
11891188

1190-
if (inInput->hasValue())
1189+
// We convert to a constant node if "in" input is a constant value or does not exist:
1190+
bool convertToConstantNode = !inInput || inInput->hasValue();
1191+
// We also convert to a constant node if every destination
1192+
// channel is constant:
1193+
// eg: "ND_swizzle_color3_color3" node with
1194+
// "010" in the "channels" input.
1195+
if (!convertToConstantNode)
1196+
{
1197+
convertToConstantNode = true;
1198+
for (size_t i = 0; i < destChannelCount; i++)
1199+
{
1200+
if (i < channelString.size())
1201+
{
1202+
if (CHANNEL_CONSTANT_MAP.count(channelString[i]))
1203+
{
1204+
// Still in constant territory:
1205+
continue;
1206+
}
1207+
}
1208+
// Every other scenario: not constant
1209+
convertToConstantNode = false;
1210+
break;
1211+
}
1212+
}
1213+
1214+
if (convertToConstantNode)
11911215
{
11921216
// Replace swizzle with constant.
11931217
node->setCategory("constant");
11941218
if (node->hasNodeDefString())
11951219
{
11961220
node->setNodeDefString("ND_constant_" + node->getType());
11971221
}
1198-
string valueString = inInput->getValueString();
1222+
string valueString = inInput ? inInput->getValueString() : "0";
11991223
StringVec origValueTokens = splitString(valueString, ARRAY_VALID_SEPARATORS);
12001224
StringVec newValueTokens;
12011225
for (size_t i = 0; i < destChannelCount; i++)
@@ -1208,25 +1232,25 @@ void Document::upgradeVersion()
12081232
if (index < origValueTokens.size())
12091233
{
12101234
newValueTokens.push_back(origValueTokens[index]);
1235+
continue;
12111236
}
12121237
}
12131238
else if (CHANNEL_CONSTANT_MAP.count(channelString[i]))
12141239
{
12151240
newValueTokens.push_back(std::to_string(CHANNEL_CONSTANT_MAP.at(channelString[i])));
1241+
continue;
12161242
}
1217-
else
1218-
{
1219-
newValueTokens.push_back(origValueTokens[0]);
1220-
}
1221-
}
1222-
else
1223-
{
1224-
newValueTokens.push_back(origValueTokens[0]);
12251243
}
1244+
// Invalid channel name, or missing channel name:
1245+
newValueTokens.push_back(origValueTokens[0]);
12261246
}
12271247
InputPtr valueInput = node->addInput("value", node->getType());
12281248
valueInput->setValueString(joinStrings(newValueTokens, ", "));
1229-
node->removeInput(inInput->getName());
1249+
// This is the last place we need to check for nullptr for inInput.
1250+
if (inInput)
1251+
{
1252+
node->removeInput(inInput->getName());
1253+
}
12301254
}
12311255
else if (destChannelCount == 1)
12321256
{
@@ -1298,17 +1322,17 @@ void Document::upgradeVersion()
12981322
{
12991323
combineInInput->setConnectedNode(separateNode);
13001324
combineInInput->setOutputString(std::string("out") + channelString[i]);
1325+
continue;
13011326
}
13021327
else if (CHANNEL_CONSTANT_MAP.count(channelString[i]))
13031328
{
13041329
combineInInput->setValue(CHANNEL_CONSTANT_MAP.at(channelString[i]));
1330+
continue;
13051331
}
13061332
}
1307-
else
1308-
{
1309-
combineInInput->setConnectedNode(separateNode);
1310-
combineInInput->setOutputString(combineInInput->isColorType() ? "outr" : "outx");
1311-
}
1333+
// Invalid channel name, or missing channel name:
1334+
combineInInput->setConnectedNode(separateNode);
1335+
combineInInput->setOutputString(inInput->isColorType() ? "outr" : "outx");
13121336
}
13131337
copyInputWithBindings(node, inInput->getName(), separateNode, "in");
13141338
node->removeInput(inInput->getName());

0 commit comments

Comments
 (0)