MaterialX icon indicating copy to clipboard operation
MaterialX copied to clipboard

Translation for specular anisotropy, rotation from Standard surface to gltf_pbr

Open bowald opened this issue 8 months ago • 0 comments

Changes

Adds translations for specular_anisotropy and specular_rotation from standardSurface to gltf_pbr

Renders

Material from AMD GPU Open MaterialX Library- Aluminum Brushed


Standard Surface - OSL Render

Translated to gltf_pbr - OSL Render
std surf - brushed aluminum - glsl
Standard Surface - GLSL MaterialXGraphEditor
gltf_pbr - brushed aluminum - glsl
Translated to gltf_pbr - GLSL MaterialXGraphEditor

Before / After PR

BEFORE-PR gltf_pbr - brushed aluminum - osl
Before PR - Translated to gltf_pbr - OSL Render

After PR - Translated to gltf_pbr - OSL Render

Description

I have created a transfer function going from standard surface input for specular_roughness, specular_anisotropy, specular_rotation to glTFs roughness, anisotropy_strength, anisotropy_rotation

Visual implementation of the added parts in the translation graph. Highlighted inputs are interfaced inputs. image

Anisotropy Strength & roughness

Roughness anisotropy defined in Standard Surface

def mx_roughness_anisotropy(roughness: float, anisotropy: float) -> tuple[float, float]:
    roughness_sqr = clamp(roughness*roughness, sys.float_info.epsilon, 1.0 )
    if anisotropy > 0.0:
        aspect = math.sqrt(1.0 - clamp(anisotropy, 0.0, 0.98))
        rx = min(roughness_sqr, aspect, 1.0)
        ry = roughness_sqr * aspect
        return (rx, ry)

    return roughness_sqr,roughness_sqr

Roughness anisotropy defined in gltf_pbr

def gltf_roughness_anisotropy(roughness: float, anisotropy: float) -> tuple[float, float]:
    alphaRoughness = clamp(roughness*roughness, sys.float_info.epsilon, 1.0 )
    at = mix(alphaRoughness, 1.0, anisotropy * anisotropy)
    ab = alphaRoughness

    return at,ab

Transfer function used in this PR

def transform_mx_to_gltf_inputs(roughness_mx: float, anisotropy_mx: float) -> tuple[float, float]:
    separate_roughness_x, separate_roughness_y = mx_roughness_anisotropy(roughness_mx, anisotropy_mx)

    roughness_gltf = math.sqrt(separate_roughness_y)

    numerator = separate_roughness_x - separate_roughness_y
    denominator = 1.0 - separate_roughness_y

    if denominator <= 0:
        anisotropy_gltf = 0.0
    else:
        anisotropy_gltf_sq = numerator / denominator
        anisotropy_gltf = math.sqrt(anisotropy_gltf_sq)

    return roughness_gltf, anisotropy_gltf

Plots of the results

mx_roughness_anisotropy
mx_roughness_anisotropy
gltf_roughness_anisotropy
gltf_roughness_anisotropy
translated_standard_surface_to_gltf_anisotropy_roughness
transform_mx_to_gltf_inputs -> gltf_roughness_anisotropy

Anisotropy Rotation

Standard surface have it's rotation maped between [0-1] where 1 is a complete rotation, in the MaterialX implementation it's currently in clockwise direction. Note that it may change: #2083

glTF uses radiance, i.e a complete rotation is 2*PI, glTF rotation is defined as counter-clockwise.

Transfer function is implemented as a multiplication with negative 2*PI

Sources

bowald avatar Jun 05 '25 15:06 bowald