Skip to content

Commit

Permalink
Adds Metal Shader Generation and Rendering Support (#1258)
Browse files Browse the repository at this point in the history
- Adds Metal Support to MaterialXShaderGen Backend
- Adds Metal Support to MaterialX Rendering code for testing generated shaders
- Adds Metal Support to MaterialXView Rendering Support (switchable between Metal and OpenGL, default is Metal)
  • Loading branch information
Morteeza authored Mar 16, 2023
1 parent 7228592 commit 6f8b3bd
Show file tree
Hide file tree
Showing 162 changed files with 14,759 additions and 1,876 deletions.
9 changes: 8 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ jobs:
compiler: xcode
compiler_version: "13.3"
python: 3.9
test_shaders: ON

- name: Windows_VS2019_Win32_Python27
os: windows-2019
Expand Down Expand Up @@ -202,16 +203,22 @@ jobs:
python Scripts/generateshader.py ../resources/Materials/Examples/StandardSurface --path .. --target glsl
python Scripts/generateshader.py ../resources/Materials/Examples/StandardSurface --path .. --target osl
python Scripts/generateshader.py ../resources/Materials/Examples/StandardSurface --path .. --target mdl
python Scripts/generateshader.py ../resources/Materials/Examples/StandardSurface --path .. --target msl
working-directory: python

- name: Shader Validation Tests
- name: Shader Validation Tests (Windows)
if: matrix.test_shaders == 'ON' && runner.os == 'Windows'
run: |
vcpkg/vcpkg install glslang --triplet=x64-windows
glslangValidator.exe -v
python python/Scripts/generateshader.py resources/Materials/Examples/StandardSurface --path . --target glsl --validator glslangValidator.exe --vulkanGlsl True --validatorArgs="-V --aml"
python python/Scripts/generateshader.py resources/Materials/Examples/StandardSurface --path . --target essl --validator glslangValidator.exe
- name: Shader Validation Tests (MacOS)
if: matrix.test_shaders == 'ON' && runner.os == 'macOS'
run: |
python python/Scripts/generateshader.py resources/Materials/Examples/StandardSurface --path . --target msl --validator "xcrun metal --language=metal" --validatorArgs="-w"
- name: Static Analysis Tests
if: matrix.static_analysis == 'ON' && runner.os == 'Linux'
run: |
Expand Down
11 changes: 10 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ option(MATERIALX_BUILD_DOCS "Create HTML documentation using Doxygen. Requires t
option(MATERIALX_BUILD_GEN_GLSL "Build the GLSL shader generator back-end." ON)
option(MATERIALX_BUILD_GEN_OSL "Build the OSL shader generator back-end." ON)
option(MATERIALX_BUILD_GEN_MDL "Build the MDL shader generator back-end." ON)
option(MATERIALX_BUILD_GEN_MSL "Build the MSL shader generator back-end." ON)
option(MATERIALX_BUILD_RENDER "Build the MaterialX Render modules." ON)
option(MATERIALX_BUILD_OIIO "Build OpenImageIO support for MaterialXRender." OFF)
option(MATERIALX_BUILD_TESTS "Build unit tests." ON)
Expand Down Expand Up @@ -105,6 +106,7 @@ mark_as_advanced(MATERIALX_BUILD_DOCS)
mark_as_advanced(MATERIALX_BUILD_GEN_GLSL)
mark_as_advanced(MATERIALX_BUILD_GEN_OSL)
mark_as_advanced(MATERIALX_BUILD_GEN_MDL)
mark_as_advanced(MATERIALX_BUILD_GEN_MSL)
mark_as_advanced(MATERIALX_BUILD_RENDER)
mark_as_advanced(MATERIALX_BUILD_OIIO)
mark_as_advanced(MATERIALX_BUILD_TESTS)
Expand Down Expand Up @@ -235,7 +237,7 @@ add_subdirectory(source/MaterialXFormat)

# Add shader generation subdirectories
add_subdirectory(source/MaterialXGenShader)
if(MATERIALX_BUILD_GEN_GLSL OR MATERIALX_BUILD_GEN_OSL OR MATERIALX_BUILD_GEN_MDL)
if(MATERIALX_BUILD_GEN_GLSL OR MATERIALX_BUILD_GEN_OSL OR MATERIALX_BUILD_GEN_MDL OR MATERIALX_BUILD_GEN_MSL)
if (MATERIALX_BUILD_GEN_GLSL)
add_definitions(-DMATERIALX_BUILD_GEN_GLSL)
add_subdirectory(source/MaterialXGenGlsl)
Expand All @@ -248,6 +250,10 @@ if(MATERIALX_BUILD_GEN_GLSL OR MATERIALX_BUILD_GEN_OSL OR MATERIALX_BUILD_GEN_MD
add_definitions(-DMATERIALX_BUILD_GEN_MDL)
add_subdirectory(source/MaterialXGenMdl)
endif()
if (MATERIALX_BUILD_GEN_MSL)
add_definitions(-DMATERIALX_BUILD_GEN_MSL)
add_subdirectory(source/MaterialXGenMsl)
endif()
add_subdirectory(libraries)
endif()

Expand All @@ -258,6 +264,9 @@ if(MATERIALX_BUILD_RENDER)
if (MATERIALX_BUILD_GEN_GLSL)
add_subdirectory(source/MaterialXRenderGlsl)
endif()
if (APPLE AND MATERIALX_BUILD_GEN_MSL)
add_subdirectory(source/MaterialXRenderMsl)
endif()
if (MATERIALX_BUILD_GEN_OSL)
add_subdirectory(source/MaterialXRenderOsl)
endif()
Expand Down
13 changes: 13 additions & 0 deletions libraries/lights/genmsl/lights_genmsl_impl.mtlx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<materialx version="1.37">

<!-- <point_light> -->
<implementation name="IM_point_light_genmsl" nodedef="ND_point_light" file="mx_point_light.metal" function="mx_point_light" target="genmsl"/>

<!-- <directional_light> -->
<implementation name="IM_directional_light_genmsl" nodedef="ND_directional_light" file="mx_directional_light.metal" function="mx_directional_light" target="genmsl"/>

<!-- <spot_light> -->
<implementation name="IM_spot_light_genmsl" nodedef="ND_spot_light" file="mx_spot_light.metal" function="mx_spot_light" target="genmsl"/>

</materialx>
5 changes: 5 additions & 0 deletions libraries/lights/genmsl/mx_directional_light.metal
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
void mx_directional_light(LightData light, float3 position, thread lightshader& result)
{
result.direction = -light.direction;
result.intensity = light.color * light.intensity;
}
8 changes: 8 additions & 0 deletions libraries/lights/genmsl/mx_point_light.metal
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
void mx_point_light(LightData light, float3 position, thread lightshader& result)
{
result.direction = light.position - position;
float distance = length(result.direction) + M_FLOAT_EPS;
float attenuation = pow(distance + 1.0, light.decay_rate + M_FLOAT_EPS);
result.intensity = light.color * light.intensity / attenuation;
result.direction /= distance;
}
13 changes: 13 additions & 0 deletions libraries/lights/genmsl/mx_spot_light.metal
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
void mx_spot_light(LightData light, float3 position, thread lightshader& result)
{
result.direction = light.position - position;
float distance = length(result.direction) + M_FLOAT_EPS;
float attenuation = pow(distance + 1.0, light.decay_rate + M_FLOAT_EPS);
result.intensity = light.color * light.intensity / attenuation;
result.direction /= distance;
float low = min(light.inner_angle, light.outer_angle);
float high = light.inner_angle;
float cosDir = dot(result.direction, -light.direction);
float spotAttenuation = smoothstep(low, high, cosDir);
result.intensity *= spotAttenuation;
}
30 changes: 25 additions & 5 deletions libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,26 @@ struct FresnelData

// Refraction
bool refraction;

#ifdef __METAL__
FresnelData(int _model = 0,
vec3 _ior = vec3(0.0f),
vec3 _extinction = vec3(0.0f),
vec3 _F0 = vec3(0.0f),
vec3 _F90 = vec3(0.0f),
float _exponent = 0.0f,
float _tf_thickness = 0.0f,
float _tf_ior = 0.0f,
bool _refraction = false) :
model(_model),
ior(_ior),
extinction(_extinction),
F0(_F0), F90(_F90), exponent(_exponent),
tf_thickness(_tf_thickness),
tf_ior(_tf_ior),
refraction(_refraction) {}
#endif

};

// https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf
Expand Down Expand Up @@ -333,11 +353,12 @@ void mx_fresnel_dielectric_phase_polarized(float cosTheta, float eta1, float eta
// Phase shift due to a conducting material
void mx_fresnel_conductor_phase_polarized(float cosTheta, float eta1, vec3 eta2, vec3 kappa2, out vec3 phiP, out vec3 phiS)
{
if (kappa2 == vec3(0, 0, 0) && eta2.x == eta2.y && eta2.y == eta2.z) {
if (dot(kappa2, kappa2) == 0.0 && eta2.x == eta2.y && eta2.y == eta2.z) {
// Use dielectric formula to increase performance
mx_fresnel_dielectric_phase_polarized(cosTheta, eta1, eta2.x, phiP.x, phiS.x);
phiP = phiP.xxx;
phiS = phiS.xxx;
float phiPx, phiSx;
mx_fresnel_dielectric_phase_polarized(cosTheta, eta1, eta2.x, phiPx, phiSx);
phiP = vec3(phiPx, phiPx, phiPx);
phiS = vec3(phiSx, phiSx, phiSx);
return;
}
vec3 k2 = kappa2 / eta2;
Expand Down Expand Up @@ -415,7 +436,6 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne

// Optical path difference
float D = 2.0 * eta2 * d * cosTheta2;
vec3 Dphi = 2.0 * M_PI * D / vec3(580.0, 550.0, 450.0);

float phi21p, phi21s;
vec3 phi23p, phi23s, r123s, r123p;
Expand Down
74 changes: 74 additions & 0 deletions libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?xml version="1.0"?>
<materialx version="1.38">

<!-- <oren_nayar_diffuse_bsdf> -->
<implementation name="IM_oren_nayar_diffuse_bsdf_genmsl" nodedef="ND_oren_nayar_diffuse_bsdf" file="../genglsl/mx_oren_nayar_diffuse_bsdf.glsl" function="mx_oren_nayar_diffuse_bsdf" target="genmsl" />

<!-- <burley_diffuse_bsdf> -->
<implementation name="IM_burley_diffuse_bsdf_genmsl" nodedef="ND_burley_diffuse_bsdf" file="../genglsl/mx_burley_diffuse_bsdf.glsl" function="mx_burley_diffuse_bsdf" target="genmsl" />

<!-- <translucent_bsdf> -->
<implementation name="IM_translucent_bsdf_genmsl" nodedef="ND_translucent_bsdf" file="../genglsl/mx_translucent_bsdf.glsl" function="mx_translucent_bsdf" target="genmsl" />

<!-- <dielectric_bsdf> -->
<implementation name="IM_dielectric_bsdf_genmsl" nodedef="ND_dielectric_bsdf" file="../genglsl/mx_dielectric_bsdf.glsl" function="mx_dielectric_bsdf" target="genmsl" />

<!-- <conductor_bsdf> -->
<implementation name="IM_conductor_bsdf_genmsl" nodedef="ND_conductor_bsdf" file="../genglsl/mx_conductor_bsdf.glsl" function="mx_conductor_bsdf" target="genmsl" />

<!-- <generalized_schlick_bsdf> -->
<implementation name="IM_generalized_schlick_bsdf_genmsl" nodedef="ND_generalized_schlick_bsdf" file="../genglsl/mx_generalized_schlick_bsdf.glsl" function="mx_generalized_schlick_bsdf" target="genmsl" />

<!-- <subsurface_bsdf> -->
<implementation name="IM_subsurface_bsdf_genmsl" nodedef="ND_subsurface_bsdf" file="../genglsl/mx_subsurface_bsdf.glsl" function="mx_subsurface_bsdf" target="genmsl" />

<!-- <sheen_bsdf> -->
<implementation name="IM_sheen_bsdf_genmsl" nodedef="ND_sheen_bsdf" file="../genglsl/mx_sheen_bsdf.glsl" function="mx_sheen_bsdf" target="genmsl" />

<!-- <anisotropic_vdf> -->
<implementation name="IM_anisotropic_vdf_genmsl" nodedef="ND_anisotropic_vdf" file="../genglsl/mx_anisotropic_vdf.glsl" function="mx_anisotropic_vdf" target="genmsl" />

<!-- <thin_film_bsdf> -->
<implementation name="IM_thin_film_bsdf_genmsl" nodedef="ND_thin_film_bsdf" target="genmsl" />

<!-- <layer> -->
<implementation name="IM_layer_bsdf_genmsl" nodedef="ND_layer_bsdf" target="genmsl" />
<implementation name="IM_layer_vdf_genmsl" nodedef="ND_layer_vdf" target="genmsl" />

<!-- <mix> -->
<implementation name="IM_mix_bsdf_genmsl" nodedef="ND_mix_bsdf" target="genmsl" />
<implementation name="IM_mix_edf_genmsl" nodedef="ND_mix_edf" target="genmsl" />

<!-- <add> -->
<implementation name="IM_add_bsdf_genmsl" nodedef="ND_add_bsdf" target="genmsl" />
<implementation name="IM_add_edf_genmsl" nodedef="ND_add_edf" target="genmsl" />

<!-- <multiply> -->
<implementation name="IM_multiply_bsdfC_genmsl" nodedef="ND_multiply_bsdfC" target="genmsl" />
<implementation name="IM_multiply_bsdfF_genmsl" nodedef="ND_multiply_bsdfF" target="genmsl" />
<implementation name="IM_multiply_edfC_genmsl" nodedef="ND_multiply_edfC" target="genmsl" />
<implementation name="IM_multiply_edfF_genmsl" nodedef="ND_multiply_edfF" target="genmsl" />

<!-- <uniform_edf> -->
<implementation name="IM_uniform_edf_genmsl" nodedef="ND_uniform_edf" file="../genglsl/mx_uniform_edf.glsl" function="mx_uniform_edf" target="genmsl" />

<!-- <surface> -->
<implementation name="IM_surface_genmsl" nodedef="ND_surface" target="genmsl" />

<!-- <displacement> -->
<implementation name="IM_displacement_float_genmsl" nodedef="ND_displacement_float" file="../genglsl/mx_displacement_float.glsl" function="mx_displacement_float" target="genmsl" />
<implementation name="IM_displacement_vector3_genmsl" nodedef="ND_displacement_vector3" file="../genglsl/mx_displacement_vector3.glsl" function="mx_displacement_vector3" target="genmsl" />

<!-- <light> -->
<implementation name="IM_light_genmsl" nodedef="ND_light" target="genmsl" />

<!-- <roughness_anisotropy> -->
<implementation name="IM_roughness_anisotropy_genmsl" nodedef="ND_roughness_anisotropy" file="../genglsl/mx_roughness_anisotropy.glsl" function="mx_roughness_anisotropy" target="genmsl" />

<!-- <roughness_dual> -->
<implementation name="IM_roughness_dual_genmsl" nodedef="ND_roughness_dual" file="../genglsl/mx_roughness_dual.glsl" function="mx_roughness_dual" target="genmsl" />

<!-- <artistic_ior> -->
<implementation name="IM_artistic_ior_genmsl" nodedef="ND_artistic_ior" file="../genglsl/mx_artistic_ior.glsl" function="mx_artistic_ior" target="genmsl" />

</materialx>
2 changes: 1 addition & 1 deletion libraries/stdlib/genglsl/lib/mx_transform_color.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ vec3 mx_srgb_texture_to_lin_rec709(vec3 color)
bvec3 isAbove = greaterThan(color, vec3(0.04045));
vec3 linSeg = color / 12.92;
vec3 powSeg = pow(max(color + vec3(0.055), vec3(0.0)) / 1.055, vec3(2.4));
return mix(linSeg, powSeg, isAbove);
return mix(linSeg, powSeg, vec3(isAbove));
}
107 changes: 107 additions & 0 deletions libraries/stdlib/genmsl/lib/mx_math.metal
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#define M_FLOAT_EPS 1e-8

float mx_square(float x)
{
return x*x;
}

vec2 mx_square(vec2 x)
{
return x*x;
}

vec3 mx_square(vec3 x)
{
return x*x;
}

#ifdef __DECL_GL_MATH_FUNCTIONS__

float radians(float degree) { return (degree * M_PI_F / 180.0f); }

float3x3 inverse(float3x3 m)
{
float n11 = m[0][0], n12 = m[1][0], n13 = m[2][0];
float n21 = m[0][1], n22 = m[1][1], n23 = m[2][1];
float n31 = m[0][2], n32 = m[1][2], n33 = m[2][2];

float det = determinant(m);
float idet = 1.0f / det;

float3x3 ret;

ret[0][0] = idet * (n22 * n33 - n32 * n23);
ret[1][0] = idet * (n32 * n13 - n12 * n33);
ret[2][0] = idet * (n12 * n23 - n22 * n13);

ret[0][1] = idet * (n31 * n23 - n21 * n33);
ret[1][1] = idet * (n11 * n33 - n31 * n13);
ret[2][1] = idet * (n21 * n13 - n11 * n23);

ret[0][2] = idet * (n21 * n32 - n31 * n22);
ret[1][2] = idet * (n31 * n12 - n11 * n32);
ret[2][2] = idet * (n11 * n22 - n21 * n12);

return ret;
}

float4x4 inverse(float4x4 m)
{
float n11 = m[0][0], n12 = m[1][0], n13 = m[2][0], n14 = m[3][0];
float n21 = m[0][1], n22 = m[1][1], n23 = m[2][1], n24 = m[3][1];
float n31 = m[0][2], n32 = m[1][2], n33 = m[2][2], n34 = m[3][2];
float n41 = m[0][3], n42 = m[1][3], n43 = m[2][3], n44 = m[3][3];

float t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44;
float t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44;
float t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44;
float t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;

float det = determinant(m);
float idet = 1.0f / det;

float4x4 ret;

ret[0][0] = t11 * idet;
ret[0][1] = (n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44) * idet;
ret[0][2] = (n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44) * idet;
ret[0][3] = (n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43) * idet;

ret[1][0] = t12 * idet;
ret[1][1] = (n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44) * idet;
ret[1][2] = (n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44) * idet;
ret[1][3] = (n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43) * idet;

ret[2][0] = t13 * idet;
ret[2][1] = (n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44) * idet;
ret[2][2] = (n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44) * idet;
ret[2][3] = (n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43) * idet;

ret[3][0] = t14 * idet;
ret[3][1] = (n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34) * idet;
ret[3][2] = (n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34) * idet;
ret[3][3] = (n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33) * idet;

return ret;
}

template<class T1, class T2>
T1 mod(T1 x, T2 y)
{
return x - y * floor(x/y);
}

template <typename T>
T atan(T y_over_x) { return ::atan(y_over_x); }

template <typename T>
T atan(T y, T x) { return ::atan2(y, x); }

#define lessThan(a, b) ((a) < (b))
#define lessThanEqual(a, b) ((a) <= (b))
#define greaterThan(a, b) ((a) > (b))
#define greaterThanEqual(a, b) ((a) >= (b))
#define equal(a, b) ((a) == (b))
#define notEqual(a, b) ((a) != (b))

#endif
Loading

0 comments on commit 6f8b3bd

Please sign in to comment.