Last active
January 17, 2021 08:08
-
-
Save mike-neko/6ed7ba3fe83bcf0418a6f5e682e6138a to your computer and use it in GitHub Desktop.
Model I/Oで立体図形のメッシュを生成する
This file contains 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 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