Skip to content

Commit 38c3633

Browse files
authored
Merge branch 'AcademySoftwareFoundation:main' into uri_for_viewer
2 parents 526ac38 + 3694c47 commit 38c3633

59 files changed

Lines changed: 509 additions & 175 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/main.yml

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@ on:
77
pull_request:
88
paths-ignore:
99
- '**.md'
10+
schedule:
11+
# Nightly build
12+
- cron: '30 10 * * *'
1013
workflow_dispatch:
1114

1215
jobs:
1316

1417
build:
1518
name: Build
1619
runs-on: ${{ matrix.os }}
20+
env:
21+
IS_EXTENDED_BUILD: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
1722
strategy:
1823
fail-fast: false
1924
matrix:
@@ -109,6 +114,7 @@ jobs:
109114
python: 3.13
110115
cmake_config: -G "Visual Studio 17 2022" -A "x64"
111116
test_shaders: ON
117+
extended_build_oiio: ON
112118

113119
- name: Windows_VS2022_x64_SharedLibs
114120
os: windows-2025
@@ -156,11 +162,10 @@ jobs:
156162
Add-Content $env:GITHUB_PATH "$PWD/build/installed/bin"
157163
158164
- name: Install OpenImageIO
159-
if: matrix.build_oiio == 'ON' && runner.os == 'Windows'
165+
if: env.IS_EXTENDED_BUILD == 'true' && matrix.extended_build_oiio == 'ON' && runner.os == 'Windows'
160166
run: |
161-
C:/vcpkg/vcpkg install openimageio --triplet=x64-windows-release
162-
Add-Content $env:GITHUB_PATH "C:/vcpkg/installed/x64-windows-release/bin"
163-
Add-Content $env:GITHUB_PATH "C:/vcpkg/installed/x64-windows-release/share/openimageio"
167+
C:/vcpkg/vcpkg install openimageio --triplet=x64-windows
168+
Add-Content $env:GITHUB_PATH "C:/vcpkg/installed/x64-windows/bin"
164169
165170
- name: Install Python ${{ matrix.python }}
166171
if: matrix.python != 'None'
@@ -178,7 +183,12 @@ jobs:
178183
run: find source \( -name *.h -o -name *.cpp -o -name *.mm -o -name *.inl \) ! -path "*/External/*" ! -path "*/NanoGUI/*" | xargs clang-format -i --verbose
179184

180185
- name: CMake Generate
181-
run: cmake -S . -B build -DMATERIALX_BUILD_PYTHON=ON -DMATERIALX_BUILD_VIEWER=ON -DMATERIALX_BUILD_GRAPH_EDITOR=ON -DMATERIALX_BUILD_TESTS=ON -DMATERIALX_TEST_RENDER=OFF -DMATERIALX_WARNINGS_AS_ERRORS=ON ${{matrix.cmake_config}}
186+
shell: bash
187+
run: |
188+
if [ "${{ env.IS_EXTENDED_BUILD }}" == "true" ] && [ "${{ matrix.extended_build_oiio }}" == "ON" ]; then
189+
EXTENDED_BUILD_CONFIG="-DMATERIALX_BUILD_OIIO=ON -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows"
190+
fi
191+
cmake -S . -B build -DMATERIALX_BUILD_PYTHON=ON -DMATERIALX_BUILD_VIEWER=ON -DMATERIALX_BUILD_GRAPH_EDITOR=ON -DMATERIALX_BUILD_TESTS=ON -DMATERIALX_TEST_RENDER=OFF -DMATERIALX_WARNINGS_AS_ERRORS=ON $EXTENDED_BUILD_CONFIG ${{matrix.cmake_config}}
182192
183193
- name: CMake Build
184194
run: cmake --build build --target install --config Release --parallel 2

CONTRIBUTING.md

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,96 @@ in the ASWF Slack or in TSC meetings before any PR is submitted, in order to
189189
solicit feedback, build consensus, and alert all stakeholders to be on the
190190
lookout for the eventual PR when it appears.
191191

192-
### Coding Conventions
192+
### Developer Guidelines
193+
194+
The following guidelines represent coding standards that we strive to follow
195+
in the MaterialX project. While not all existing code may adhere to these
196+
standards yet, we encourage all new contributions to follow these practices,
197+
and we welcome incremental improvements to bring existing code into alignment
198+
with these guidelines.
199+
200+
#### Naming Conventions
201+
202+
Class names should use PascalCase, as in `NodeGraph` or `ShaderGenerator`.
203+
Method names should use camelCase starting with a lowercase letter, for
204+
example `getNode` or `setName`. Protected and private member variables should
205+
use an underscore prefix, such as `_name` or `_parent`. Constants should be
206+
written in UPPER_CASE with underscores separating words, as in `EMPTY_STRING`
207+
or `CATEGORY`. Type aliases should append appropriate suffixes to indicate
208+
their purpose, using `Ptr` for pointers, `Vec` for vectors, `Map` for maps,
209+
and `Set` for sets.
210+
211+
#### Static Constants and Class Organization
212+
213+
Class members should be organized in order of decreasing visibility: public,
214+
protected, then private. Static constants should be placed at the end of their
215+
respective visibility section. String constants should be defined in implementation
216+
files rather than headers to avoid One Definition Rule violations. The
217+
`EMPTY_STRING` constant should be used instead of empty string literals (`""`)
218+
for clarity and consistency.
219+
220+
#### Smart Pointer Conventions
221+
222+
Heap-allocated objects in the public API should always use `shared_ptr` for
223+
memory management. Type aliases should be defined for all shared pointers,
224+
following the pattern of `ElementPtr` for `shared_ptr<Element>`. Both mutable
225+
and const versions of these type aliases should be provided, e.g. `ElementPtr`
226+
and `ConstElementPtr`. Raw pointers should be avoided except when representing
227+
non-owning references within implementation details.
228+
229+
#### Const Correctness
230+
231+
Methods that do not modify an object's state should be marked as `const`.
232+
Accessor methods should provide const versions to enable their use on const
233+
objects. Type aliases following the pattern `ConstElementPtr` should be used to
234+
indicate read-only access through shared pointers. Parameters that should not
235+
be modified within a function should be declared as const.
236+
237+
#### Parameter Passing and Return Values
238+
239+
Strings and complex objects should be passed by `const&` to avoid unnecessary
240+
copies. Shared pointers should be passed by value since they are designed to
241+
be cheap to copy. When returning shared pointers, they should be returned by
242+
value rather than by reference. Methods should be marked as `const` whenever
243+
they do not modify the object's state.
244+
245+
#### Exception Handling
246+
247+
Exceptions should be used for exceptional conditions rather than for normal
248+
control flow. Custom exception types should be defined by inheriting from
249+
`Exception` to represent specific error categories. Exception messages should
250+
be descriptive and include relevant context to aid in debugging. All exceptions
251+
that may be thrown by a method should be documented using the `@throws` tag in
252+
the method's documentation. When catching exceptions, specific exception types
253+
should be caught rather than generic exceptions whenever possible.
254+
255+
#### Header Includes
256+
257+
Header includes should be written with angle brackets, with paths relative to
258+
the root source folder (e.g. `#include <MaterialXCore/Element.h>`). This
259+
ensures consistent include paths across the entire codebase, regardless of the
260+
location of the referencing file.
261+
262+
Each implementation file should include its corresponding header file first,
263+
so the first include in `Element.cpp` should be `Element.h`. This ensures that
264+
the header file is self-contained and doesn't accidentally depend on includes
265+
from other headers.
266+
267+
After the corresponding header, include blocks should be ordered hierarchically,
268+
with high-level modules listed before low-level modules (e.g.
269+
`MaterialXGenShader`, followed by `MaterialXFormat`, followed by
270+
`MaterialXCore`). This maximizes opportunities to catch missing dependencies in
271+
the high-level modules, which might otherwise be hidden at build time. Within
272+
include blocks, individual includes should be ordered alphabetically, providing
273+
a simple canonical order that is straightforward for developers to check.
274+
275+
In the interest of avoiding include cycles, developers are free to leverage
276+
forward declarations of classes that are trivially referenced within another
277+
header. In the interest of clarity and efficiency, developers are free to
278+
leverage transitive header includes, where low-level headers that have already
279+
been included by a high-level header do not need to be restated individually.
280+
281+
#### Coding Style
193282

194283
The coding style of the MaterialX project is defined by a
195284
[clang-format](.clang-format) file in the repository, which is supported by
@@ -200,7 +289,18 @@ file to automatically align the code to MaterialX conventions. When modifying
200289
existing code, follow the surrounding formatting conventions so that new or
201290
modified code blends in with the current code.
202291

203-
### Unit Tests
292+
#### Documentation Standards
293+
294+
All classes and methods in the public API should be documented with Doxygen
295+
comments. Classes should be documented with the `@class` tag, and structs with
296+
the `@struct` tag, followed by a brief description and any detailed
297+
documentation. Method documentation should include `@param`, `@return`, and
298+
`@throws` tags where applicable. Related methods should be grouped together
299+
using `/// @name GroupName` sections to improve readability. File-level
300+
documentation should be placed immediately after the copyright header using
301+
the `/// @file` directive.
302+
303+
#### Unit Tests
204304

205305
Each MaterialX module has a companion folder within the
206306
[MaterialXTest](source/MaterialXTest) module, containing a set of unit tests
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"materials": [
3+
{
4+
"name": "StandardSurface",
5+
"path": "../../resources/Materials/Examples/StandardSurface",
6+
"baseURL": "Materials/Examples/StandardSurface"
7+
},
8+
{
9+
"name": "UsdPreviewSurface",
10+
"path": "../../resources/Materials/Examples/UsdPreviewSurface",
11+
"baseURL": "Materials/Examples/UsdPreviewSurface"
12+
},
13+
{
14+
"name": "GltfPbr",
15+
"path": "../../resources/Materials/Examples/GltfPbr",
16+
"baseURL": "Materials/Examples/GltfPbr"
17+
},
18+
{
19+
"name": "OpenPbr",
20+
"path": "../../resources/Materials/Examples/OpenPbr",
21+
"baseURL": "Materials/Examples/OpenPbr"
22+
}
23+
]
24+
}

javascript/MaterialXView/source/viewer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ export class Scene
182182

183183
if (!child.geometry.attributes.normal)
184184
{
185-
var startNormalTime = performance.new();
185+
var startNormalTime = performance.now();
186186
child.geometry.computeVertexNormals();
187187
normalTime += performance.now() - startNormalTime;
188188
}

javascript/MaterialXView/webpack.config.js

Lines changed: 23 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,26 @@ const fs = require('fs');
33
const CopyPlugin = require("copy-webpack-plugin");
44
const HtmlWebpackPlugin = require('html-webpack-plugin')
55

6-
const stdSurfaceMaterials = "../../resources/Materials/Examples/StandardSurface";
7-
const stdSurfaceMaterialsBaseURL = "Materials/Examples/StandardSurface";
8-
let dirent = fs.readdirSync(stdSurfaceMaterials).filter(
9-
function (file) { if (file.lastIndexOf(".mtlx") > -1) return file; }
10-
)
11-
let materials = dirent
12-
.map((fileName) => ({ name: fileName, value: `${stdSurfaceMaterialsBaseURL}/${fileName}` }));
13-
14-
const usdSurfaceMaterials = "../../resources/Materials/Examples/UsdPreviewSurface";
15-
const usdSurfaceMaterialsBaseURL = "Materials/Examples/UsdPreviewSurface";
16-
dirent = fs.readdirSync(usdSurfaceMaterials).filter(
17-
function (file) { if (file.lastIndexOf(".mtlx") > -1) return file; }
18-
)
19-
let usdMaterials = dirent
20-
.map((fileName) => ({ name: fileName, value: `${usdSurfaceMaterialsBaseURL}/${fileName}` }));
6+
// Load material configuration from external JSON file
7+
const materialConfig = JSON.parse(fs.readFileSync('./example_materials.json', 'utf8'));
218

22-
const gltfPbrMaterials = "../../resources/Materials/Examples/GltfPbr";
23-
const gltfPbrMaterialsBaseURL = "Materials/Examples/GltfPbr";
24-
dirent = fs.readdirSync(gltfPbrMaterials).filter(
25-
function (file) { if (file.lastIndexOf(".mtlx") > -1) return file; }
26-
)
27-
let gltfMaterials = dirent
28-
.map((fileName) => ({ name: fileName, value: `${gltfPbrMaterialsBaseURL}/${fileName}` }));
29-
30-
const openPbrMaterials = "../../resources/Materials/Examples/OpenPbr";
31-
const openPbrMaterialsBaseURL = "Materials/Examples/OpenPbr";
32-
dirent = fs.readdirSync(openPbrMaterials).filter(
33-
function (file) { if (file.lastIndexOf(".mtlx") > -1) return file; }
34-
)
35-
let openMaterials = dirent
36-
.map((fileName) => ({ name: fileName, value: `${openPbrMaterialsBaseURL}/${fileName}` }));
9+
// Function to process materials from a given path
10+
function processMaterialPath(materialPath, baseURL) {
11+
const dirent = fs.readdirSync(materialPath).filter(
12+
function (file) { if (file.lastIndexOf(".mtlx") > -1) return file; }
13+
);
14+
return dirent.map((fileName) => ({
15+
name: fileName,
16+
value: `${baseURL}/${fileName}`
17+
}));
18+
}
3719

38-
materials = materials.concat(usdMaterials);
39-
materials = materials.concat(gltfMaterials);
40-
materials = materials.concat(openMaterials);
20+
// Generate materials array from configuration
21+
let materials = [];
22+
materialConfig.materials.forEach(materialType => {
23+
const materialFiles = processMaterialPath(materialType.path, materialType.baseURL);
24+
materials = materials.concat(materialFiles);
25+
});
4126

4227
const geometryFiles = "../../resources/Geometry";
4328
const geometryFilesURL = "Geometry";
@@ -77,10 +62,11 @@ module.exports = {
7762
{ from: "./public", to: 'public' },
7863
{ context: "../../resources/Lights", from: "*.*", to: "Lights" },
7964
{ context: "../../resources/Lights/irradiance", from: "*.*", to: "Lights/irradiance" },
80-
{ from: stdSurfaceMaterials, to: stdSurfaceMaterialsBaseURL },
81-
{ from: usdSurfaceMaterials, to: usdSurfaceMaterialsBaseURL },
82-
{ from: gltfPbrMaterials, to: gltfPbrMaterialsBaseURL },
83-
{ from: openPbrMaterials, to: openPbrMaterialsBaseURL },
65+
// Dynamically generate material copy patterns from configuration
66+
...materialConfig.materials.map(materialType => ({
67+
from: materialType.path,
68+
to: materialType.baseURL
69+
})),
8470
{ from: "../build/bin/JsMaterialXCore.wasm" },
8571
{ from: "../build/bin/JsMaterialXCore.js" },
8672
{ from: "../build/bin/JsMaterialXGenShader.wasm" },

javascript/build_javascript_win.bat

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
@rem Edit the following paths to match your local locations for the Emscripten and MaterialX projects.
66
set EMSDK_LOCATION=C:/GitHub/emsdk
77
set MATERIALX_LOCATION=C:/GitHub/MaterialX
8-
call %EMSDK_LOCATION%/emsdk.bat install 2.0.20
9-
call %EMSDK_LOCATION%/emsdk.bat activate 2.0.20
8+
call %EMSDK_LOCATION%/emsdk.bat install 4.0.8
9+
call %EMSDK_LOCATION%/emsdk.bat activate 4.0.8
1010
if NOT ["%errorlevel%"]==["0"] pause
1111
@echo --------------------- Build MaterialX With JavaScript ---------------------
1212
@echo on

libraries/bxdf/translation/standard_surface_to_gltf_pbr.mtlx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
<input name="base" type="float" value="1" />
66
<input name="base_color" type="color3" value="0.8, 0.8, 0.8" />
77
<input name="metalness" type="float" value="0" />
8+
<input name="specular" type="float" value="1" />
9+
<input name="specular_color" type="color3" value="1, 1, 1" />
810
<input name="specular_anisotropy" type="float" value="0.0" />
911
<input name="specular_rotation" type="float" value="0.0" />
1012
<input name="specular_roughness" type="float" value="0.2" />
@@ -27,6 +29,8 @@
2729
<output name="base_color_out" type="color3" />
2830
<output name="metallic_out" type="float" />
2931
<output name="roughness_out" type="float" />
32+
<output name="specular_out" type="float" />
33+
<output name="specular_color_out" type="color3" />
3034
<output name="ior_out" type="float" />
3135
<output name="anisotropy_strength_out" type="float" />
3236
<output name="anisotropy_rotation_out" type="float" />
@@ -203,6 +207,14 @@
203207
<input name="in" type="float" interfacename="emission" />
204208
</dot>
205209

210+
<!-- Specular -->
211+
<dot name="specular" type="float">
212+
<input name="in" type="float" interfacename="specular" />
213+
</dot>
214+
<dot name="specular_color" type="color3">
215+
<input name="in" type="color3" interfacename="specular_color" />
216+
</dot>
217+
206218
<!-- Specular Index of Refraction -->
207219
<dot name="ior" type="float">
208220
<input name="in" type="float" interfacename="specular_IOR" />
@@ -236,6 +248,8 @@
236248
<output name="base_color_out" type="color3" nodename="base_color" />
237249
<output name="metallic_out" type="float" nodename="metallic" />
238250
<output name="roughness_out" type="float" nodename="roughness" />
251+
<output name="specular_out" type="float" nodename="specular" />
252+
<output name="specular_color_out" type="color3" nodename="specular_color" />
239253
<output name="ior_out" type="float" nodename="ior" />
240254
<output name="anisotropy_strength_out" type="float" nodename="anisotropy_strength" />
241255
<output name="anisotropy_rotation_out" type="float" nodename="anisotropy_rotation" />

libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ vec3 mx_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 alpha, int distributio
5959
radiance /= G1V * float(envRadianceSamples);
6060

6161
// Return the final radiance.
62-
return radiance * $envLightIntensity;
62+
return ($envRadianceSamples == 0 ? vec3(0.0) : radiance) * $envLightIntensity;
6363
}
6464

6565
vec3 mx_environment_irradiance(vec3 N)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
float mx_shadow_occlusion(
3+
$texSamplerSignature,
4+
mat4 shadow_matrix,
5+
vec3 world_position
6+
)
7+
{
8+
vec4 shadowCoord4 = mx_matrix_mul(shadow_matrix, vec4(world_position, 1.0));
9+
vec3 shadowCoord = shadowCoord4.xyz / shadowCoord4.w;
10+
shadowCoord = shadowCoord * 0.5 + 0.5;
11+
vec2 shadowMoments = texture($texSamplerSampler2D, shadowCoord.xy).xy;
12+
return mx_variance_shadow_occlusion(shadowMoments, shadowCoord.z);
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
float mx_shadow_occlusion(
3+
MetalTexture shadow_map_tex,
4+
float4x4 shadow_matrix,
5+
float3 world_position
6+
)
7+
{
8+
float4 shadowCoord4 = mx_matrix_mul(shadow_matrix, float4(world_position, 1.0));
9+
float3 shadowCoord = shadowCoord4.xyz / shadowCoord4.w;
10+
shadowCoord.xy = shadowCoord.xy * 0.5 + 0.5;
11+
float2 shadowMoments = texture(shadow_map_tex, shadowCoord.xy).xy;
12+
return mx_variance_shadow_occlusion(shadowMoments, shadowCoord.z);
13+
}

0 commit comments

Comments
 (0)