-
-
Save kahunamoore/57f3571e3a30caa3f80f0365a47db998 to your computer and use it in GitHub Desktop.
RealityKit Marching Cubes Blob (Metal + LowLevelMesh)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(¶ms, 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() } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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