Skip to content

Instantly share code, notes, and snippets.

@mike-neko
Last active January 17, 2021 08:08
Show Gist options
  • Save mike-neko/6ed7ba3fe83bcf0418a6f5e682e6138a to your computer and use it in GitHub Desktop.
Save mike-neko/6ed7ba3fe83bcf0418a6f5e682e6138a to your computer and use it in GitHub Desktop.
Model I/Oで立体図形のメッシュを生成する
#include <metal_stdlib>
using namespace metal;
#define lightDirection float3(1, -4, -5)
struct VertexInput {
float3 position [[ attribute(0) ]];
float3 normal [[ attribute(1) ]];
float2 texcoord [[ attribute(2) ]];
};
struct VertexUniforms {
float4x4 projectionViewMatrix;
float3x3 normalMatrix;
};
struct VertexOut {
float4 position [[ position ]];
float3 normal;
float2 texcoord;
};
vertex VertexOut lambertVertex(VertexInput in [[ stage_in ]],
constant VertexUniforms& uniforms [[ buffer(1) ]]) {
VertexOut out;
out.position = uniforms.projectionViewMatrix * float4(in.position, 1);
out.texcoord = float2(in.texcoord.x, in.texcoord.y);
out.normal = uniforms.normalMatrix * in.normal;
return out;
}
fragment half4 lambertFragment(VertexOut in [[ stage_in ]]) {
float diffuseFactor = saturate(dot(in.normal, -lightDirection));
return half4(diffuseFactor);
}
import MetalKit
struct FrameUniforms {
var projectionViewMatrinx: matrix_float4x4
var normalMatrinx: matrix_float3x3
}
class ViewController: NSViewController, MTKViewDelegate {
private let defaultCameraMatrix = Matrix.lookAt(eye: float3(0, 2, 6), center: float3(), up: float3(0, 1, 0))
@IBOutlet private weak var mtkView: MTKView!
private var device: MTLDevice!
private var commandQueue: MTLCommandQueue!
private var library: MTLLibrary!
private var renderState: MTLRenderPipelineState!
private var depthStencilState: MTLDepthStencilState!
private var frameUniformBuffer: MTLBuffer!
private let semaphore = DispatchSemaphore(value: 1)
private var mesh: MTKMesh!
private var modelMatrix = matrix_identity_float4x4
// MARK: -
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setupMetal()
loadModel()
mtkView.draw()
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
// MARK: -
private func setupMetal() {
device = MTLCreateSystemDefaultDevice()!
commandQueue = device.makeCommandQueue()
library = device.newDefaultLibrary()!
mtkView.sampleCount = 4
mtkView.depthStencilPixelFormat = .depth32Float_stencil8
mtkView.colorPixelFormat = .bgra8Unorm
mtkView.clearColor = MTLClearColorMake(0.3, 0.3, 0.3, 1)
mtkView.device = device
mtkView.delegate = self
let depthDescriptor = MTLDepthStencilDescriptor()
depthDescriptor.depthCompareFunction = .less
depthDescriptor.isDepthWriteEnabled = true
depthStencilState = device.makeDepthStencilState(descriptor: depthDescriptor)
frameUniformBuffer = device.makeBuffer(length: MemoryLayout<FrameUniforms>.size, options: [])
}
private func loadModel() {
let allocator = MTKMeshBufferAllocator(device: device)
let mdlMesh = MDLMesh.newBox(withDimensions: vector_float3(1),
segments: vector_uint3(2),
geometryType: .triangles,
inwardNormals: false,
allocator: allocator)
mesh = try! MTKMesh(mesh: mdlMesh, device: device)
let vertexDescriptor = MTKMetalVertexDescriptorFromModelIO(mesh.vertexDescriptor)
let renderDescriptor = MTLRenderPipelineDescriptor()
renderDescriptor.vertexDescriptor = vertexDescriptor
renderDescriptor.sampleCount = mtkView.sampleCount
renderDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat
renderDescriptor.vertexFunction = library.makeFunction(name: "lambertVertex")
renderDescriptor.fragmentFunction = library.makeFunction(name: "lambertFragment")
renderDescriptor.depthAttachmentPixelFormat = mtkView.depthStencilPixelFormat
renderDescriptor.stencilAttachmentPixelFormat = mtkView.depthStencilPixelFormat
renderState = try! device.makeRenderPipelineState(descriptor: renderDescriptor)
}
// MARK: - MTKViewDelegate
func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
}
func draw(in view: MTKView) {
autoreleasepool {
semaphore.wait()
let commandBuffer = commandQueue.makeCommandBuffer()
let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: view.currentRenderPassDescriptor!)
renderEncoder.pushDebugGroup("Render Object")
renderEncoder.setRenderPipelineState(renderState)
renderEncoder.setDepthStencilState(depthStencilState)
updateFramUniforms()
renderEncoder.setVertexBuffer(mesh.vertexBuffers[0].buffer, offset: 0, at: 0)
renderEncoder.setVertexBuffer(frameUniformBuffer, offset: 0, at: 1)
renderEncoder.drawIndexedPrimitives(type: mesh.submeshes[0].primitiveType,
indexCount: mesh.submeshes[0].indexCount,
indexType: mesh.submeshes[0].indexType,
indexBuffer: mesh.submeshes[0].indexBuffer.buffer,
indexBufferOffset: mesh.submeshes[0].indexBuffer.offset)
renderEncoder.popDebugGroup()
renderEncoder.endEncoding()
commandBuffer.present(view.currentDrawable!)
commandBuffer.addCompletedHandler { _ in
self.semaphore.signal()
}
commandBuffer.commit()
}
}
private func updateFramUniforms() {
let p = frameUniformBuffer.contents().assumingMemoryBound(to: FrameUniforms.self)
let cameraMatrix = Matrix.lookAt(eye: float3(0, 2, 4), center: float3(), up: float3(0, 1, 0))
let projectionMatrix = Matrix.perspective(fovyRadians: radians(fromDegrees: 75),
aspect: Float(mtkView.drawableSize.width / mtkView.drawableSize.height),
nearZ: 0.1,
farZ: 100)
let viewModelMatrix = matrix_multiply(cameraMatrix, modelMatrix)
p.pointee.projectionViewMatrinx = matrix_multiply(projectionMatrix, viewModelMatrix)
let mat3 = Matrix.toUpperLeft3x3(from4x4: viewModelMatrix)
p.pointee.normalMatrinx = matrix_invert(matrix_transpose(mat3))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment