ShaderGraphCoder

June 6, 2024 ยท View on GitHub

Build

Are you building the next great visionOS app? Are you also super tired of drawing shader code with boxes and lines? ShaderGraphCoder is an embedded DSL to write RealityKit shader graphs (USD compatible) in strongly typed Swift.

759 shader graph nodes are made available through 117 operators (math, blends, texture lookups, etc.) and 66 sources (constants, model and view transforms, etc.).

Supported Platforms: visionOS

Examples

// Create a solid red material for visionOS
func solidRed() async throws -> ShaderGraphMaterial {
    let color: SGColor = .color3f([1, 0, 0])
    let surface = pbrSurface(baseColor: color)
    return try await ShaderGraphMaterial(surface: surface)
}

// Create a pulsing blue material for visionOS
func pulsingBlue() async throws -> ShaderGraphMaterial {
    let frequency = SGValue.floatParameter(name: "Frequency", defaultValue: 2)
    let color: SGColor = .color3f([0, 0, 1]) * sin(SGValue.time * frequency * (2*Float.pi))
    let surface = pbrSurface(baseColor: color)
    return try await ShaderGraphMaterial(surface: surface)
}

// Create a texture mapped material for visionOS
func textureMap(textureLocalURL: URL) async throws -> ShaderGraphMaterial {
    // Create the surface by sampling the texture map
    let surface =
        SGValue
        .texture(contentsOf: textureLocalURL)
        .sampleColor3f(texcoord: SGValue.uv0)
        .pbrSurface()
    return try await ShaderGraphMaterial(surface: surface)
}

Shader Preview using SwiftUI

Thanks to the powerful SwiftUI integration with RealityKit, you can preview your shaders in the Xcode canvas.

Shader previews are made available through the ShaderGraphPreview view. You can either embed it into your existing SwiftUI views or just use the #Preview macro to see the shader in action.

Here is an example of how to embed the preview in your own view:

import SwiftUI
import ShaderGraphCoder

struct MyView: View {
    /// Create a blue surface shader
    let blueSurface = SGValue.color3f([0, 0, 1]).pbrSurface()
    var body: some View {
        // Preview the surface using ShaderGraphPreview
        ShaderGraphPreview(surface: blueSurface)
    }
}

Or you can just use a preview:

#Preview {
    let blueSurface = SGValue.color3f([0, 0, 1]).pbrSurface()
    return ShaderGraphPreview(surface: blueSurface)
}

This will show a blue box and a blue sphere in the Xcode canvas:

ShaderGraphPreview

All 100+ shader operations are supported and it's a really fun environment to play around in.

How it Works

When you write your shader code using the provided SGValue types, each operation on those values builds up a shader graph. The graph starts with source values (parameters, constants, and world info) and each operation extends the graph by adding nodes and edges. Each node in that graph is an operation, and each edge is a value. When you create a ShaderGraphMaterial from this graph, the graph is compiled into a USDA material that is then loaded by RealityKit.

Values

The following value types are supported:

TypeDescription
SGValueBase value type
SGNumeric: SGValueBase class for numeric types scalar, vector, and color
SGScalar: SGNumericA single number
SGSIMD: SGNumericBase class for SIMD types color and vector
SGColor: SGSIMDA vector of color values, with either 3 or 4 elements
SGVector: SGSIMDA vector of values, with either 2, 3, or 4 elements
SGMatrix: SGNumericA square matrix with either 2, 3, or 4 dimensions
SGTexture: SGValueA 2D texture that can be sampled or read
SGToken: SGValueA surface shader or geometry modifier

Each of these Swift types has an underlying graph data type available as dataType.

For more details see Values.swift.

Operations

There are over 100 operators that combine SGScalar, SGVector, SGColor, and SGMatrix values in varied and wonderful ways. From simple arithmetic to complex blends, a bit of everything is available.

The ifGreaterOrEqual and ifLess operators are conditional operators that take a condition, a value if true, and a value if false. The mix operator is a linear interpolation operator that takes two values and a weight. Since runtime conditionals are not supported in RealityKit, the ifGreaterOrEqual and ifLess operators are the best way to implement runtime logic.

The following operators are supported:

OperatorDescription
+Addition
-Subtraction
*Multiplication
/Division
%Modulo
&&Logical And
||Logical Or
^^Logical Xor
abs(in1)Abs
acos(in1)Acos
add(in1, in2)Add
ambientOcclusion(coneangle, maxdistance)Ambient Occlusion
asin(in1)Asin
atan2(iny, inx)Atan2
blur(in1, size, ...)Blur
burn(fg, bg, ...)Burn
ceil(in1)Ceiling
cellNoise2D(texcoord)Cellular Noise 2D
cellNoise3D(position)Cellular Noise 3D
clamp(in1, min, ...)Clamp
contrast(in1, amount, ...)Contrast
cos(in1)Cos
cross(in1, in2)Cross Product
determinant(in1)Determinant
difference(fg, bg, ...)Difference
disjointover(fg, bg, ...)Disjoint Over
divide(in1, in2)Divide
dodge(fg, bg, ...)Dodge
dot(in1, in2)Dot Product
exp(in1)Exp
extract(in1, index)Extract
floor(in1)Floor
fract(in1)Fractional
fractal3D(amplitude, octaves, ...)Fractal Noise 3D
geometryModifier(modelPositionOffset, color, ...)Geometry Modifier
geometrySwitchCameraIndex(mono, left, ...)Camera Index Switch
heightToNormal(in1, scale)Height To Normal
hsvAdjust(in1, amount)HSV Adjust
hsvToRGB(in1)HSV to RGB
ifEqual(value1, value2, ...)If Equal
ifGreater(value1, value2, ...)If Greater
ifGreaterOrEqual(value1, value2, ...)If Greater Or Equal
image(file, defaultValue, ...)Image
inside(in1, mask)Inside
invertMatrix(in1)Invert Matrix
length(in1)Magnitude
log(in1)Natural Log
logicalAnd(in1, in2)And
logicalNot(in1)Not
logicalOr(in1, in2)Or
logicalXor(in1, in2)XOR
luminance(in1, lumacoeffs)Luminance
mask(fg, bg, ...)Mask
matte(fg, bg, ...)Matte
max(in1, in2)Max
min(in1, in2)Min
minus(fg, bg, ...)Subtractive Mix
mix(fg, bg, ...)Mix
mixColor(fg, bg, ...)In
modulo(in1, in2)Modulo
multiply(in1, in2)Multiply
noise2D(amplitude, pivot, ...)Noise 2D
noise3D(amplitude, pivot, ...)Noise 3D
normalMap(in1, space, ...)Normal Map
normalMapDecode(in1)Normal Map Decode
normalize(in1)Normalize
oneMinus(in1)One Minus
out(fg, bg, ...)Out
outside(in1, mask)Outside
over(fg, bg, ...)Over
overlay(fg, bg, ...)Overlay
pbrSurface(baseColor, emissiveColor, ...)PBR Surface
pixel(file, uWrapMode, ...)Image 2D Pixel
pixelGradient(file, uWrapMode, ...)Image 2D Gradient Pixel
pixelLOD(file, uWrapMode, ...)Image 2D LOD Pixel
place2D(texcoord, pivot, ...)Place 2D
plus(fg, bg, ...)Additive Mix
pow(in1, in2)Power
premult(in1)Premultiply
ramp4(valuetl, valuetr, ...)Ramp 4 Corners
ramplr(valuel, valuer, ...)Ramp Horizontal
ramptb(valuet, valueb, ...)Ramp Vertical
range(in1, inlow, ...)Range
read(file, defaultValue, ...)Image 2D Read
reflect(in1, normal)Reflect
refract(in1, normal, ...)Refract
remap(in1, inlow, ...)Remap
rgbToHSV(in1)RGB to HSV
rotate2D(in1, amount)Rotate 2D
rotate3D(in1, amount, ...)Rotate 3D
round(in1)Round
safePow(in1, in2)Safe Power
sample(file, uWrapMode, ...)Image 2D
sampleCube(file, uWrapMode, ...)Cube Image
sampleCubeGradient(file, uWrapMode, ...)Cube Image Gradient
sampleCubeLOD(file, uWrapMode, ...)Cube Image LOD
sampleGradient(file, uWrapMode, ...)Image 2D Gradient
sampleLOD(file, uWrapMode, ...)Image 2D LOD
saturate(in1, amount, ...)Saturate
screen(fg, bg, ...)Screen
sign(in1)Sign
sin(in1)Sin
smoothStep(in1, low, ...)Smooth Step
splitlr(valuel, valuer, ...)Split Horizontal
splittb(valuet, valueb, ...)Split Vertical
sqrt(in1)Square Root
step(in1, edge)Step
subtract(in1, in2)Subtract
switchValue(in1, in2, ...)Switch
tan(in1)Tan
tiledImage(file, defaultValue, ...)Tiled Image
transformMatrix(in1, mat)Transform Matrix
transformNormal(in1, fromspace, ...)Transform Normal
transformPoint(in1, fromspace, ...)Transform Point
transformVector(in1, fromspace, ...)Transform Vector
transpose(in1)Transpose
triplanarProjection(filex, filey, ...)Triplanar Projection
unlitSurface(color, opacity, ...)Unlit Surface
unpremult(in1)Unpremultiply
worleyNoise2DFloat(texcoord, jitter)Worley Noise 2D
worleyNoise2DVector2(texcoord, jitter)Worley Noise 2D
worleyNoise2DVector3(texcoord, jitter)Worley Noise 2D
worleyNoise3DFloat(position, jitter)Worley Noise 3D
worleyNoise3DVector2(position, jitter)Worley Noise 3D
worleyNoise3DVector3(position, jitter)Worley Noise 3D

For more details see Operations.swift and Operations.g.swift.

Sources

The following sources are supported:

SourceDescription
SGValue.color3fA constant RGB color with an optional color space
SGValue.color3fParameterAn RGB color parameter that can be set by later mutating the material
SGValue.color4fA constant RGBA color with an optional color space
SGValue.color4fParameterAn RGBA color parameter that can be set by later mutating the material
SGValue.surfaceCustomAttributeA value passed from the geometry modifier to the surface shader
SVValue.floatA constant floating point number
SGValue.floatParameterA parameter that can be set by later mutating the material
SGValue.modelNormalThe model normal of the vertex or fragment being processed
SGValue.modelPositionThe model position of the vertex or fragment being processed
SGValue.objectNormalThe object normal of the vertex or fragment being processed
SGValue.objectPositionThe object position of the vertex or fragment being processed
SGValue.textureParameterA 2D texture parameter that can be set by later mutating the material
SGValue.uv(index)UV coordinate of the vertex or pixel
SGValue.uv0The first UV coordinate of the vertex or pixel
SGValue.uv1The second UV coordinate of the vertex or pixel
SGValue.vector2fA constant 2D vector
SGValue.vector2fParameterA 2D vector parameter that can be set by later mutating the material
SGValue.vector3fA constant 3D vector
SGValue.vector3fParameterA 3D vector parameter that can be set by later mutating the material
SGValue.vector4fA constant 4D vector
SGValue.vector4fParameterA 4D vector parameter that can be set by later mutating the material
SGValue.worldCameraPositionThe world position of the camera
SGValue.worldNormalThe world normal of the vertex or fragment being processed
SGValue.worldPositionThe world position of the vertex or fragment being processed
SGValue.bitangent(space, index)Bitangent
SGValue.cameraPosition(space)Camera Position
SGValue.frameFrame
SGValue.geomcolorColor3(index)Geometry Color
SGValue.geomcolorColor4(index)Geometry Color
SGValue.geomcolorFloat(index)Geometry Color
SGValue.geometryModifierCustomAttributeGeometry Modifier Custom Attribute
SGValue.geometryModifierCustomAttributeHalf20Geometry Modifier Custom Attribute 0
SGValue.geometryModifierCustomAttributeHalf21Geometry Modifier Custom Attribute 1
SGValue.geometryModifierCustomAttributeHalf40Geometry Modifier Custom Attribute 0
SGValue.geometryModifierCustomAttributeHalf41Geometry Modifier Custom Attribute 1
SGValue.geometryModifierCustomAttributeHalf42Geometry Modifier Custom Attribute 2
SGValue.geometryModifierCustomAttributeHalf43Geometry Modifier Custom Attribute 3
SGValue.geometryModifierCustomParameterGeometry Modifier Custom Parameter
SGValue.geometryModifierModelPositionOffsetGeometry Modifier Model Position Offset
SGValue.geometryModifierModelToViewGeometry Modifier Model To View
SGValue.geometryModifierModelToWorldGeometry Modifier Model To World
SGValue.geometryModifierNormalToWorldGeometry Modifier Normal To World
SGValue.geometryModifierProjectionToViewGeometry Modifier Projection To View
SGValue.geometryModifierUV0OffsetGeometry Modifier uv0 Offset
SGValue.geometryModifierUV0TransformGeometry Modifier uv0 Transform
SGValue.geometryModifierUV1OffsetGeometry Modifier uv1 Offset
SGValue.geometryModifierUV1TransformGeometry Modifier uv1 Transform
SGValue.geometryModifierVertexIdGeometry Modifier Vertex ID
SGValue.geometryModifierViewToProjectionGeometry Modifier View To Projection
SGValue.geometryModifierWorldToModelGeometry Modifier World To Model
SGValue.materialParametersBaseColorTintMaterial Parameter Base Color Tint
SGValue.materialParametersClearcoatRoughnessScaleMaterial Parameter Roughness Scale
SGValue.materialParametersClearcoatScaleMaterial Parameter Clearcoat Scale
SGValue.materialParametersEmissiveColorMaterial Parameter Emissive Color
SGValue.materialParametersMetallicScaleMaterial Parameter Metallic Scale
SGValue.materialParametersOpacityScaleMaterial Parameter Opacity Scale
SGValue.materialParametersOpacityThresholdMaterial Parameter Opacity Threshold
SGValue.materialParametersRoughnessScaleMaterial Parameter Roughness Scale
SGValue.materialParametersSpecularScaleMaterial Parameter Specular Scale
SGValue.normal(space)Normal
SGValue.position(space)Position
SGValue.surfaceBaseColorSurface Base Color
SGValue.surfaceClearcoatSurface Clearcoat
SGValue.surfaceClearcoatRoughnessSurface Clearcoat Roughness
SGValue.surfaceCustomAttributeSurface Custom Attribute
SGValue.surfaceCustomAttributeHalf20Surface Custom Attribute 0
SGValue.surfaceCustomAttributeHalf21Surface Custom Attribute 1
SGValue.surfaceCustomAttributeHalf40Surface Custom Attribute 0
SGValue.surfaceCustomAttributeHalf41Surface Custom Attribute 1
SGValue.surfaceCustomAttributeHalf42Surface Custom Attribute 2
SGValue.surfaceCustomAttributeHalf43Surface Custom Attribute 3
SGValue.surfaceCustomParameterSurface Custom Parameter
SGValue.surfaceEmissiveColorSurface Emissive Color
SGValue.surfaceMetallicSurface Metallic
SGValue.surfaceModelToViewSurface Model To View
SGValue.surfaceModelToWorldSurface Model To World
SGValue.surfaceOpacitySurface Opacity
SGValue.surfaceProjectionToViewSurface Projection To View
SGValue.surfaceRoughnessSurface Roughness
SGValue.surfaceScreenPositionSurface Screen Position
SGValue.surfaceSpecularSurface Specular
SGValue.surfaceViewDirectionSurface View Direction
SGValue.surfaceViewToProjectionSurface View To Projection
SGValue.surfaceWorldToViewSurface World To View
SGValue.tangent(space, index)Tangent
SGValue.texcoordVector2(index)Texture Coordinates
SGValue.texcoordVector3(index)Texture Coordinates
SGValue.timeTime
SGValue.upDirection(space)Up Direction
SGValue.viewDirection(space)View Direction

For more details see Sources.swift and Sources.g.swift.

Building on the Command Line

visionOS

xcodebuild -scheme ShaderGraphCoder -destination 'platform=visionOS Simulator,OS=1.0,name=Apple Vision Pro'