Skip to content

Anisotropy

glTF extension: KHR_materials_anisotropy
glTF properties: anisotropyStrength · anisotropyRotation · anisotropyTexture

Anisotropy stretches specular highlights along a tangent direction, simulating surfaces such as brushed metal, hair, or satin fabric. Requires KHR_materials_anisotropy to be enabled in the export options.

Shader Strength attr Rotation attr
standardSurface, aiStandardSurface specularAnisotropy (or anisotropy) specularRotation (or anisotropyRotation)
openPBRSurface specularRoughnessAnisotropy plugin-managed custom specularRotation
StingrayPBS not supported not supported

The exporter checks the Standard Surface and Arnold-family strength and rotation attribute names in priority order: specularAnisotropy before anisotropy, and specularRotation before anisotropyRotation.

openPBRSurface is still a partial case: the importer maps anisotropy strength to the native OpenPBR anisotropy control, and preserves glTF anisotropyRotation in a plugin-managed custom specularRotation attribute. That preserves round-trip export fidelity, but it is not the same as native OpenPBR shading support for the rotation value.

The glTF anisotropy texture is a packed RGB image:

Channel Data
R Anisotropy direction X
G Anisotropy direction Y
B Anisotropy strength

Anisotropy strength

Factor only

Set the shader's anisotropy-strength attribute directly:

standardSurface, aiStandardSurface: shader.specularAnisotropy or shader.anisotropy
openPBRSurface: shader.specularRoughnessAnisotropy

Exports as anisotropyStrength. Only written when the value is greater than 0.0.

Texture only

Color space: Raw

Use the anisotropy texture path for both of these workflows:

  • a packed glTF anisotropy map where R/G store direction and B stores strength
  • separate grayscale source images that are lane-mapped through the first multiplyDivide and packed during export

For packed glTF anisotropy maps, use one RGB texture with this channel layout:

  • R = direction X
  • G = direction Y
  • B = strength

For separate grayscale source images, use this lane mapping:

direction X source -> multiplyDivide1.input1X
direction Y source -> multiplyDivide1.input1Y
strength source    -> multiplyDivide1.input1Z

For true grayscale source images, you can use outColor, outColorR, outColorG, or outColorB, because all RGB channels contain the same value. The lane still determines the result: input1X exports as packed R, input1Y exports as packed G, and input1Z exports as packed B.


Anisotropy rotation

Scalar value only

Set specularRotation (or anisotropyRotation) directly on the shader.

The exporter converts the value to radians using these heuristics:

  • Value in [−1, 1]: treated as normalized turns → multiplied by 2π
  • Value in [−360, 360]: treated as degrees → converted to radians
  • Otherwise: assumed to already be in radians

For standardSurface and aiStandardSurface, rotation is only exported when anisotropy strength is also active (factor > 0 or texture present). Exports as anisotropyRotation.

openPBRSurface importer-authored materials preserve anisotropy rotation in the custom specularRotation attribute and emit a warning that the value is being kept for round-trip export rather than native shader evaluation.

Via the packed anisotropy texture (importer-generated graph)

When a glTF file with anisotropy is imported, the importer builds a specific node graph to decode the packed texture. The exporter recognizes this graph on re-export and reconstructs the packed RGB anisotropy texture precisely.

Strength chain:

anisotropyTexture
  → multiplyDivide1.input1{X,Y,Z}
  → multiplyDivide1.output
  → plusMinusAverage1.input3D[0]
  → plusMinusAverage1.output3Dz
  → multiplyDivide2.input1X
(strength scalar) → multiplyDivide2.input2X
  → multiplyDivide2.outputX
  → shader anisotropy-strength attr

Rotation chain:

plusMinusAverage1.output3Dx/y
  → aiAtan
  → plusMinusAverage2.input3D[0]
(rotation offset in degrees) → plusMinusAverage2.input3D[1]
  → plusMinusAverage2.output3D
  → multiplyDivide3.input1
(2π) → multiplyDivide3.input2
  → multiplyDivide3.outputX
  → shader rotation attr

The exporter reads multiplyDivide2.input2X as anisotropyStrength, and the rotation degrees offset from plusMinusAverage2 as anisotropyRotation (converted to radians). If the three input channels of multiplyDivide1 come from separate grayscale textures, the exporter packs them into a new RGB image (R = X channel, G = Y channel, B = Z channel).

If the anisotropy graph uses nondefault banding, the exporter also rebakes packed anisotropy textures on export so the packed direction map stays aligned with the exported anisotropyRotation value.

Separate grayscale source images (exporter-authored packing)

The exporter also supports authoring anisotropy from separate grayscale source images and packing them into one glTF anisotropy texture during export.

Use the first multiplyDivide node as the semantic lane mapper:

X lane: source -> multiplyDivide1.input1X -> packed anisotropyTexture.R -> direction X
Y lane: source -> multiplyDivide1.input1Y -> packed anisotropyTexture.G -> direction Y
Z lane: source -> multiplyDivide1.input1Z -> packed anisotropyTexture.B -> strength

For true grayscale source images, the exporter can trace outColor, outColorR, outColorG, or outColorB, because all RGB channels contain the same value. The semantic meaning still comes from the destination lane on the first multiplyDivide:

  • multiplyDivide1.input1X means tangent-space direction X and exports to packed R
  • multiplyDivide1.input1Y means tangent-space direction Y and exports to packed G
  • multiplyDivide1.input1Z means anisotropy strength and exports to packed B

Recommended lane wiring:

direction X map -> multiplyDivide1.input1X
direction Y map -> multiplyDivide1.input1Y
strength map    -> multiplyDivide1.input1Z

This lane mapping applies equally to standardSurface, aiStandardSurface, and openPBRSurface. Only the final shader attrs differ:

  • standardSurface, aiStandardSurface: multiplyDivide2.outputX -> shader.specularAnisotropy, multiplyDivide3.outputX -> shader.specularRotation
  • openPBRSurface: multiplyDivide2.outputX -> shader.specularRoughnessAnisotropy, multiplyDivide3.outputX -> shader.specularRotation

UV transform

file nodes: set repeat, wrap, mirror, offset, and rotation on the connected place2dTexture.
aiImage nodes: wrap, scale, and offset export natively; rotation requires a place2dTexture.

UV set: assign via Maya's UV Set Editor or UV Linking - see UV Set Selection for node-type differences.


Notes

  • Always use Raw color space for anisotropy textures.
  • The packed glTF anisotropy texture uses R/G = direction XY and B = strength.
  • For true grayscale sources, the exporter can accept outColor, outColorR, outColorG, or outColorB, but the first multiplyDivide lane still determines the packed glTF meaning: X -> R/direction X, Y -> G/direction Y, Z -> B/strength.
  • For separate grayscale anisotropy maps, wire direction X to multiplyDivide1.input1X, direction Y to multiplyDivide1.input1Y, and strength to multiplyDivide1.input1Z.
  • Rotation is only exported when anisotropy strength is active.
  • The exporter probes Standard Surface and Arnold-family attribute names in priority order: specularAnisotropy before anisotropy, and specularRotation before anisotropyRotation.
  • Imported openPBRSurface materials keep anisotropy strength and preserve anisotropy rotation in the custom specularRotation attribute for round-trip export.
  • Round-tripped materials (imported from glTF then re-exported) are handled by an importer-graph detection path that reconstructs the packed texture. When anisotropy banding differs from the default, the exporter rebakes the packed map so the exported texture and rotation stay in sync.
  • StingrayPBS does not export KHR_materials_anisotropy.