Skip to content

Instantly share code, notes, and snippets.

@kahunamoore
Forked from Matt54/MarchingCubesBlobParams.h
Created August 20, 2025 20:59
Show Gist options
  • Save kahunamoore/57f3571e3a30caa3f80f0365a47db998 to your computer and use it in GitHub Desktop.
Save kahunamoore/57f3571e3a30caa3f80f0365a47db998 to your computer and use it in GitHub Desktop.
RealityKit Marching Cubes Blob (Metal + LowLevelMesh)
#ifndef edgeTable_h
#define edgeTable_h
constant int edgeTable[256]={
0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac,
0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c,
0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc,
0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c,
0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 };
#endif /* edgeTable_h */
#include <metal_stdlib>
using namespace metal;
#include "VertexPositionNormal.h"
#include "MarchingCubesBlobParams.h"
#include "edgeTable.h"
#include "triTable.h"
inline float3 interpolateIsoSurfacePosition(float3 pA, float valueA,
float3 pB, float valueB,
float isoLevel) {
float denom = (valueB - valueA);
float t = (isoLevel - valueA) / (denom + 1e-6f);
return mix(pA, pB, clamp(t, 0.0f, 1.0f));
}
inline float sdf_sphere(float3 p, float3 c, float r) {
return length(p - c) - r;
}
inline float smin(float a, float b, float k) {
float h = clamp(0.5f + 0.5f * (b - a) / max(k, 1e-6f), 0.0f, 1.0f);
return mix(b, a, h) - k * h * (1.0f - h);
}
inline float fieldValue(float3 worldPos,
constant MarchingCubesBlobParams& P,
device const Sphere* spheres) {
float d = 1e9f;
uint count = P.sphereCount;
for (uint i = 0; i < count; ++i) {
float di = sdf_sphere(worldPos, spheres[i].center, spheres[i].radius);
d = smin(d, di, P.smoothK);
}
return d;
}
inline float3 estimateNormalFromField(float3 worldPos,
constant MarchingCubesBlobParams& P,
device const Sphere* spheres) {
float h = 0.5f * min(P.cellSize.x, min(P.cellSize.y, P.cellSize.z));
float fx = fieldValue(worldPos + float3(h,0,0), P, spheres) - fieldValue(worldPos - float3(h,0,0), P, spheres);
float fy = fieldValue(worldPos + float3(0,h,0), P, spheres) - fieldValue(worldPos - float3(0,h,0), P, spheres);
float fz = fieldValue(worldPos + float3(0,0,h), P, spheres) - fieldValue(worldPos - float3(0,0,h), P, spheres);
return normalize(float3(fx, fy, fz) / (2.0f * h));
}
kernel void generateMarchingCubesBlobMesh(device VertexPositionNormal* outVertices [[buffer(0)]],
device uint* outIndices [[buffer(1)]],
device atomic_uint* outVertexCounter [[buffer(2)]],
constant MarchingCubesBlobParams& P [[buffer(3)]],
device const Sphere* spheres [[buffer(4)]],
uint3 cellCoord [[thread_position_in_grid]]) {
if (cellCoord.x >= P.cells.x || cellCoord.y >= P.cells.y || cellCoord.z >= P.cells.z) {
return;
}
const int3 cornerOffsets[8] = {
int3(0,0,0), int3(1,0,0), int3(1,1,0), int3(0,1,0),
int3(0,0,1), int3(1,0,1), int3(1,1,1), int3(0,1,1)
};
const int2 edgeCornerIndexPairs[12] = {
int2(0,1), int2(1,2), int2(2,3), int2(3,0),
int2(4,5), int2(5,6), int2(6,7), int2(7,4),
int2(0,4), int2(1,5), int2(2,6), int2(3,7)
};
const float3 cellOriginWS = P.origin + float3(cellCoord) * P.cellSize;
float cornerScalar[8];
float3 cornerPositionWS[8];
for (int i = 0; i < 8; ++i) {
float3 cp = cellOriginWS + float3(cornerOffsets[i]) * P.cellSize;
cornerPositionWS[i] = cp;
cornerScalar[i] = fieldValue(cp, P, spheres);
}
int cubeIndex = 0;
if (cornerScalar[0] > P.isoLevel) cubeIndex |= 1;
if (cornerScalar[1] > P.isoLevel) cubeIndex |= 2;
if (cornerScalar[2] > P.isoLevel) cubeIndex |= 4;
if (cornerScalar[3] > P.isoLevel) cubeIndex |= 8;
if (cornerScalar[4] > P.isoLevel) cubeIndex |= 16;
if (cornerScalar[5] > P.isoLevel) cubeIndex |= 32;
if (cornerScalar[6] > P.isoLevel) cubeIndex |= 64;
if (cornerScalar[7] > P.isoLevel) cubeIndex |= 128;
int edgeMask = edgeTable[cubeIndex];
if (edgeMask == 0) { return; }
float3 edgeIntersectionWS[12];
for (int edge = 0; edge < 12; ++edge) {
if (edgeMask & (1 << edge)) {
const int a = edgeCornerIndexPairs[edge].x;
const int b = edgeCornerIndexPairs[edge].y;
edgeIntersectionWS[edge] = interpolateIsoSurfacePosition(
cornerPositionWS[a], cornerScalar[a],
cornerPositionWS[b], cornerScalar[b],
P.isoLevel
);
}
}
constant int* triangleEdgesRow = &triTable[cubeIndex][0];
for (int triIdx = 0; triIdx < 16 && triangleEdgesRow[triIdx] != -1; triIdx += 3) {
const int e0 = triangleEdgesRow[triIdx + 0];
const int e1 = triangleEdgesRow[triIdx + 1];
const int e2 = triangleEdgesRow[triIdx + 2];
const float3 p0 = edgeIntersectionWS[e0];
const float3 p1 = edgeIntersectionWS[e1];
const float3 p2 = edgeIntersectionWS[e2];
const float3 n0 = estimateNormalFromField(p0, P, spheres);
const float3 n1 = estimateNormalFromField(p1, P, spheres);
const float3 n2 = estimateNormalFromField(p2, P, spheres);
const uint baseVertexIndex = atomic_fetch_add_explicit(outVertexCounter, (uint)3, memory_order_relaxed);
outVertices[baseVertexIndex + 0].position = p0;
outVertices[baseVertexIndex + 0].normal = n0;
outVertices[baseVertexIndex + 1].position = p1;
outVertices[baseVertexIndex + 1].normal = n1;
outVertices[baseVertexIndex + 2].position = p2;
outVertices[baseVertexIndex + 2].normal = n2;
outIndices[baseVertexIndex + 0] = baseVertexIndex + 0;
outIndices[baseVertexIndex + 1] = baseVertexIndex + 1;
outIndices[baseVertexIndex + 2] = baseVertexIndex + 2;
}
}
#ifndef MarchingCubesBlobParams_h
#define MarchingCubesBlobParams_h
#include <simd/simd.h>
typedef struct {
simd_float3 center;
float radius;
} Sphere;
typedef struct {
simd_uint3 cells;
simd_float3 origin;
simd_float3 cellSize;
float isoLevel;
uint32_t sphereCount;
float smoothK;
} MarchingCubesBlobParams;
#endif /* MarchingCubesBlobParams_h */
import Metal
import RealityKit
import SwiftUI
struct MarchingCubesBlobView: View {
@State var entity: Entity?
@State var mesh: LowLevelMesh?
@State var positions: [SIMD3<Float>] = []
@State var targets: [SIMD3<Float>] = []
@State var radii: [Float] = []
@State var speeds: [Float] = []
@State var smoothK: Float = 0.06
@State var speed: Float = 0.25
@State var sphereCountUI: Int = 24
@State var targetRadius: Float = 0.0125
@State var radiusVariance: Float = 0.125
@State var radianceRoughness: Float = 0.12
@State var materialRoughness: Float = 0.33
@State var eta: Float = 0.2
@State var specular: Float = 0.12
@State var timer: Timer?
@State var lastFrameTime = CACurrentMediaTime()
// Grid sizing (similar pattern to single-shape example)
let volumeRadius: Float = 0.175
var cellsPerAxis: UInt32 = 80
var cells: SIMD3<UInt32> { SIMD3<UInt32>(cellsPerAxis, cellsPerAxis, cellsPerAxis) }
var cellSize: SIMD3<Float> {
let ratio = volumeRadius / Float(cellsPerAxis) * 2
return SIMD3<Float>(ratio, ratio, ratio)
}
// Spheres
let maxSpheres = 64
struct SphereData {
var center: SIMD3<Float>
var radius: Float
}
// Metal
let device: MTLDevice
let commandQueue: MTLCommandQueue
let computePipelineState: MTLComputePipelineState
let vertexCountBuffer: MTLBuffer
let spheresBuffer: MTLBuffer
enum ShaderGraphParameter: String {
case radianceRoughness
case materialRoughness
case eta
case specular
}
init() {
let device = MTLCreateSystemDefaultDevice()!
self.device = device
self.commandQueue = device.makeCommandQueue()!
let library = device.makeDefaultLibrary()!
let function = library.makeFunction(name: "generateMarchingCubesBlobMesh")!
self.computePipelineState = try! device.makeComputePipelineState(function: function)
self.vertexCountBuffer = device.makeBuffer(length: MemoryLayout<UInt32>.stride, options: .storageModeShared)!
self.spheresBuffer = device.makeBuffer(length: maxSpheres * MemoryLayout<SphereData>.stride, options: .storageModeShared)!
}
var body: some View {
VStack(spacing: 40) {
RealityView { content in
let maxCellCount = Int(cells.x * cells.y * cells.z)
let vertexCapacity = 15 * maxCellCount
let indexCapacity = vertexCapacity
let lowLevelMesh = try! VertexPositionNormal.initializeMesh(vertexCapacity: vertexCapacity,
indexCapacity: indexCapacity)
let meshResource = try! await MeshResource(from: lowLevelMesh)
let material = try! await getMaterial()
let entity = ModelEntity(mesh: meshResource, materials: [material])
content.add(entity)
self.mesh = lowLevelMesh
self.entity = entity
await removeDefaultIBL()
reseedSpheres(count: sphereCountUI)
startTimer()
}
.onDisappear { stopTimer() }
VStack {
HStack {
Text("Spheres: \(sphereCountUI)")
Spacer()
Slider(value: Binding(get: { Double(sphereCountUI) },
set: { newVal in
sphereCountUI = Int(newVal)
reseedSpheres(count: sphereCountUI)
}),
in: 1...Double(maxSpheres), step: 1)
.frame(width: 300)
}
HStack {
Text("Target Radius: \(targetRadius, specifier: "%.4f")")
Spacer()
Slider(value: Binding(get: { Double(targetRadius) },
set: { newVal in
targetRadius = Float(newVal)
reseedSpheres(count: sphereCountUI)
}),
in: 0.005...0.05)
.frame(width: 300)
}
HStack {
Text("Radius Variance: \(radiusVariance*100, specifier: "%.1f")%")
Spacer()
Slider(value: Binding(get: { Double(radiusVariance) },
set: { newVal in
radiusVariance = Float(newVal)
reseedSpheres(count: sphereCountUI)
}),
in: 0.0...1.0)
.frame(width: 300)
}
HStack {
Text("Smooth K: \(smoothK, specifier: "%.3f")")
Spacer()
Slider(value: $smoothK, in: 0.0...0.12)
.frame(width: 300)
}
HStack {
Text("Speed: \(speed, specifier: "%.2f")")
Spacer()
Slider(value: $speed, in: 0.0...1.0)
.frame(width: 300)
}
HStack {
Text("Radiance Rough: \(radianceRoughness, specifier: "%.2f")")
Spacer()
Slider(value: $radianceRoughness, in: 0...0.4)
.frame(width: 300)
}
.onChange(of: radianceRoughness) {
try? setShaderGraphParameterValue(.radianceRoughness, value: radianceRoughness)
}
HStack {
Text("Material Rough: \(materialRoughness, specifier: "%.2f")")
Spacer()
Slider(value: $materialRoughness, in: 0...0.4)
.frame(width: 300)
}
.onChange(of: materialRoughness) {
try? setShaderGraphParameterValue(.materialRoughness, value: materialRoughness)
}
HStack {
Text("ETA: \(eta, specifier: "%.2f")")
Spacer()
Slider(value: $eta, in: 0...1)
.frame(width: 300)
}
.onChange(of: eta) {
try? setShaderGraphParameterValue(.eta, value: eta)
}
HStack {
Text("Specular: \(specular, specifier: "%.2f")")
Spacer()
Slider(value: $specular, in: 0...1)
.frame(width: 300)
}
.onChange(of: specular) {
try? setShaderGraphParameterValue(.specular, value: specular)
}
}
.frame(width: 500)
.padding()
.glassBackgroundEffect()
}
}
}
// MARK: Timer / Animation
extension MarchingCubesBlobView {
func startTimer() {
stopTimer()
lastFrameTime = CACurrentMediaTime()
timer = Timer.scheduledTimer(withTimeInterval: 1.0 / 60.0, repeats: true) { _ in
let now = CACurrentMediaTime()
let deltaTime = max(0.0, now - lastFrameTime)
lastFrameTime = now
updateSpheres(deltaTime: Float(deltaTime))
updateMesh()
}
}
func stopTimer() {
timer?.invalidate()
timer = nil
}
}
// MARK: Sphere Size and Position
extension MarchingCubesBlobView {
private func randomPositionWithPadding() -> SIMD3<Float> {
let gridSizeWorldSpace = SIMD3<Float>(Float(cells.x), Float(cells.y), Float(cells.z)) * cellSize
let minWorldSpace = -0.5 * gridSizeWorldSpace
let maxWorldSpace = minWorldSpace + gridSizeWorldSpace
// Add padding to prevent spheres from going too close to edges
// smoothK increases size so we increase padding to compensate
let padding: Float = volumeRadius * (0.3+smoothK*3)
let paddedMin = minWorldSpace + padding
let paddedMax = maxWorldSpace - padding
return SIMD3<Float>(
Float.random(in: paddedMin.x...paddedMax.x),
Float.random(in: paddedMin.y...paddedMax.y),
Float.random(in: paddedMin.z...paddedMax.z)
)
}
func reseedSpheres(count: Int) {
// Calculate min/max radius based on target and variance
let varianceAmount = targetRadius * radiusVariance
let minR = targetRadius - varianceAmount
let maxR = targetRadius + varianceAmount
positions = (0..<count).map { _ in randomPositionWithPadding() }
targets = (0..<count).map { _ in randomPositionWithPadding() }
radii = (0..<count).map { _ in Float.random(in: minR...maxR) }
speeds = (0..<count).map { _ in Float.random(in: 0.5...1.5) }
}
func updateSpheres(deltaTime: Float) {
guard positions.count == sphereCountUI else { return }
for sphereIndex in 0..<sphereCountUI {
let currentPosition = positions[sphereIndex]
let targetPosition = targets[sphereIndex]
var direction = targetPosition - currentPosition
let distance = simd_length(direction)
if distance < 1e-5 {
targets[sphereIndex] = randomPositionWithPadding()
continue
}
direction /= distance
let movementStep = speed * speeds[sphereIndex] * deltaTime * volumeRadius * 1.5
if movementStep >= distance {
positions[sphereIndex] = targetPosition
targets[sphereIndex] = randomPositionWithPadding()
} else {
positions[sphereIndex] = currentPosition + direction * movementStep
}
}
// Write spheres to buffer
let sphereDataPointer = spheresBuffer.contents().bindMemory(to: SphereData.self, capacity: maxSpheres)
for sphereIndex in 0..<sphereCountUI {
sphereDataPointer[sphereIndex] = SphereData(center: positions[sphereIndex], radius: radii[sphereIndex])
}
}
}
// MARK: Mesh
extension MarchingCubesBlobView {
func updateMesh() {
guard let mesh = mesh,
let commandBuffer = commandQueue.makeCommandBuffer(),
let computeEncoder = commandBuffer.makeComputeCommandEncoder()
else { return }
let gridSizeWorldSpace = SIMD3<Float>(Float(cells.x), Float(cells.y), Float(cells.z)) * cellSize
let gridMinCornerWorldSpace = -0.5 * gridSizeWorldSpace
let gridMaxCornerWorldSpace = gridMinCornerWorldSpace + gridSizeWorldSpace
var params = MarchingCubesBlobParams(
cells: cells,
origin: gridMinCornerWorldSpace,
cellSize: cellSize,
isoLevel: 0.0,
sphereCount: UInt32(sphereCountUI),
smoothK: smoothK
)
// Reset vertex counter
vertexCountBuffer.contents().bindMemory(to: UInt32.self, capacity: 1).pointee = 0
// Acquire GPU-backed mesh buffers
let vertexBuffer = mesh.replace(bufferIndex: 0, using: commandBuffer)
let indexBuffer = mesh.replaceIndices(using: commandBuffer)
// Encode compute
computeEncoder.setComputePipelineState(computePipelineState)
computeEncoder.setBuffer(vertexBuffer, offset: 0, index: 0)
computeEncoder.setBuffer(indexBuffer, offset: 0, index: 1)
computeEncoder.setBuffer(vertexCountBuffer, offset: 0, index: 2)
computeEncoder.setBytes(&params, length: MemoryLayout<MarchingCubesBlobParams>.stride, index: 3)
computeEncoder.setBuffer(spheresBuffer, offset: 0, index: 4)
let threadsPerThreadgroup = MTLSize(width: 8, height: 8, depth: 4)
let threadgroups = MTLSize(
width: (Int(cells.x) + threadsPerThreadgroup.width - 1) / threadsPerThreadgroup.width,
height: (Int(cells.y) + threadsPerThreadgroup.height - 1) / threadsPerThreadgroup.height,
depth: (Int(cells.z) + threadsPerThreadgroup.depth - 1) / threadsPerThreadgroup.depth
)
computeEncoder.dispatchThreadgroups(threadgroups, threadsPerThreadgroup: threadsPerThreadgroup)
computeEncoder.endEncoding()
commandBuffer.commit()
commandBuffer.waitUntilCompleted()
let vertexCount = Int(vertexCountBuffer.contents().bindMemory(to: UInt32.self, capacity: 1).pointee)
mesh.parts.replaceAll([
LowLevelMesh.Part(indexCount: vertexCount,
topology: .triangle,
bounds: BoundingBox(min: gridMinCornerWorldSpace, max: gridMaxCornerWorldSpace))
])
}
}
// MARK: Material
// See: https://developer.apple.com/documentation/visionos/implementing-adjustable-material-in-visionos
extension MarchingCubesBlobView {
func getMaterial() async throws -> ShaderGraphMaterial {
let baseURL = URL(string: "https://matt54.github.io/Resources/")!
let fullURL = baseURL.appendingPathComponent("GlassScene.usda")
let data = try Data(contentsOf: fullURL)
let materialPath: String = "/Root/GlassMaterial"
var material = try await ShaderGraphMaterial(named: materialPath, from: data)
try! material.setParameter(name: ShaderGraphParameter.radianceRoughness.rawValue,
value: .float(radianceRoughness))
try! material.setParameter(name: ShaderGraphParameter.materialRoughness.rawValue, value: .float(materialRoughness))
try! material.setParameter(name: ShaderGraphParameter.eta.rawValue, value: .float(eta))
try! material.setParameter(name: ShaderGraphParameter.specular.rawValue, value: .float(specular))
return material
}
func setShaderGraphParameterValue(_ parameter: ShaderGraphParameter, value: Float) throws {
guard let entity = entity else { return }
guard let modelComponent = entity.components[ModelComponent.self] else { return }
guard var material = modelComponent.materials.first as? ShaderGraphMaterial else { return }
try material.setParameter(name: parameter.rawValue, value: .float(value))
entity.components[ModelComponent.self]?.materials = [material]
}
}
// MARK: Environment Lighting / IBL
extension MarchingCubesBlobView {
func removeDefaultIBL() async {
guard let entity else { return }
let cgImage = createSimpleIBLTexture(size: CGSize(width: 256, height: 128), color: CGColor(gray: 0, alpha: 0))!
let greyscaleEnvironmentResource = try! await EnvironmentResource(equirectangular: cgImage)
let source: ImageBasedLightComponent.Source = .single(greyscaleEnvironmentResource)
let iblComponent = ImageBasedLightComponent(
source: source,
intensityExponent: 1
)
entity.components[ImageBasedLightComponent.self] = iblComponent
entity.components.set(ImageBasedLightReceiverComponent(imageBasedLight: entity))
}
func createSimpleIBLTexture(size: CGSize, color: CGColor) -> CGImage? {
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
guard let context = CGContext(data: nil,
width: Int(size.width),
height: Int(size.height),
bitsPerComponent: 8,
bytesPerRow: 0,
space: colorSpace,
bitmapInfo: bitmapInfo.rawValue) else {
return nil
}
context.setFillColor(color)
context.fill(CGRect(origin: .zero, size: size))
return context.makeImage()
}
}
#Preview { MarchingCubesBlobView() }
#ifndef triTable_h
#define triTable_h
constant int triTable[256][16] =
{{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
{3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
{3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
{3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
{9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
{2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
{8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
{4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
{3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
{1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
{4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
{4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
{5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
{2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
{9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
{0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
{2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
{10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
{5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
{5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
{9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
{1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
{10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
{8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
{2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
{7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
{2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
{11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
{5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
{11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
{11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
{9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
{2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
{6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
{3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
{6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
{10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
{6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
{8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
{7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
{3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
{0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
{9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
{8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
{5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
{0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
{6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
{10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
{10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
{8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
{1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
{0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
{10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
{3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
{6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
{9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
{8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
{3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
{6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
{0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
{10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
{10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
{2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
{7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
{7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
{2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
{1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
{11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
{8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
{0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
{7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
{10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
{2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
{6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
{7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
{2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
{10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
{10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
{0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
{7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
{6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
{8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
{9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
{6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
{4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
{10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
{8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
{0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
{1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
{8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
{10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
{4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
{10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
{11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
{9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
{6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
{7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
{3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
{7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
{3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
{6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
{9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
{1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
{4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
{7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
{6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
{3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
{0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
{6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
{0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
{11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
{6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
{5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
{9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
{1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
{1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
{10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
{0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
{5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
{10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
{11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
{9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
{7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
{2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
{8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
{9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
{9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
{1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
{9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
{5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
{0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
{10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
{2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
{0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
{0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
{9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
{5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
{3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
{5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
{8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
{0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
{9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
{1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
{3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
{4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
{9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
{11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
{11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
{2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
{9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
{3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
{1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
{4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
{3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
{0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
{1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}};
#endif /* triTable_h */
import Foundation
import RealityKit
extension VertexPositionNormal {
static var vertexAttributes: [LowLevelMesh.Attribute] = [
.init(semantic: .position, format: .float3, offset: MemoryLayout<Self>.offset(of: \.position)!),
.init(semantic: .normal, format: .float3, offset: MemoryLayout<Self>.offset(of: \.normal)!)
]
static var vertexLayouts: [LowLevelMesh.Layout] = [
.init(bufferIndex: 0, bufferStride: MemoryLayout<Self>.stride)
]
static var descriptor: LowLevelMesh.Descriptor {
var desc = LowLevelMesh.Descriptor()
desc.vertexAttributes = VertexPositionNormal.vertexAttributes
desc.vertexLayouts = VertexPositionNormal.vertexLayouts
desc.indexType = .uint32
return desc
}
@MainActor static func initializeMesh(vertexCapacity: Int,
indexCapacity: Int) throws -> LowLevelMesh {
var desc = VertexPositionNormal.descriptor
desc.vertexCapacity = vertexCapacity
desc.indexCapacity = indexCapacity
return try LowLevelMesh(descriptor: desc)
}
}
#include <simd/simd.h>
#ifndef VertexPositionNormal_h
#define VertexPositionNormal_h
struct VertexPositionNormal {
simd_float3 position;
simd_float3 normal;
};
#endif /* VertexPositionNormal_h */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment