Extract Terrain into its own class
This commit is contained in:
parent
ee2431d9c4
commit
5fa89d1e47
3 changed files with 89 additions and 62 deletions
|
|
@ -23,6 +23,7 @@
|
||||||
C0C15AB9218E2A90007494E2 /* Shaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = C0C15AB8218E2A90007494E2 /* Shaders.metal */; };
|
C0C15AB9218E2A90007494E2 /* Shaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = C0C15AB8218E2A90007494E2 /* Shaders.metal */; };
|
||||||
C0C15ABC218E2A90007494E2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C0C15ABB218E2A90007494E2 /* Assets.xcassets */; };
|
C0C15ABC218E2A90007494E2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C0C15ABB218E2A90007494E2 /* Assets.xcassets */; };
|
||||||
C0C15ABF218E2A90007494E2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C0C15ABD218E2A90007494E2 /* Main.storyboard */; };
|
C0C15ABF218E2A90007494E2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C0C15ABD218E2A90007494E2 /* Main.storyboard */; };
|
||||||
|
C0C15AC6218E32B3007494E2 /* Terrain.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0C15AC5218E32B2007494E2 /* Terrain.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
|
@ -49,6 +50,7 @@
|
||||||
C0C15ABE218E2A90007494E2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
C0C15ABE218E2A90007494E2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||||
C0C15AC0218E2A90007494E2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
C0C15AC0218E2A90007494E2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
C0C15AC1218E2A90007494E2 /* Terrain2.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Terrain2.entitlements; sourceTree = "<group>"; };
|
C0C15AC1218E2A90007494E2 /* Terrain2.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Terrain2.entitlements; sourceTree = "<group>"; };
|
||||||
|
C0C15AC5218E32B2007494E2 /* Terrain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Terrain.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
|
@ -122,6 +124,7 @@
|
||||||
C0C15AB2218E2A90007494E2 /* AppDelegate.swift */,
|
C0C15AB2218E2A90007494E2 /* AppDelegate.swift */,
|
||||||
C0C15AB4218E2A90007494E2 /* GameViewController.swift */,
|
C0C15AB4218E2A90007494E2 /* GameViewController.swift */,
|
||||||
C0C15AB6218E2A90007494E2 /* Renderer.swift */,
|
C0C15AB6218E2A90007494E2 /* Renderer.swift */,
|
||||||
|
C0C15AC5218E32B2007494E2 /* Terrain.swift */,
|
||||||
C0C15AB8218E2A90007494E2 /* Shaders.metal */,
|
C0C15AB8218E2A90007494E2 /* Shaders.metal */,
|
||||||
C0C15ABA218E2A90007494E2 /* ShaderTypes.h */,
|
C0C15ABA218E2A90007494E2 /* ShaderTypes.h */,
|
||||||
C0C15ABB218E2A90007494E2 /* Assets.xcassets */,
|
C0C15ABB218E2A90007494E2 /* Assets.xcassets */,
|
||||||
|
|
@ -247,6 +250,7 @@
|
||||||
files = (
|
files = (
|
||||||
C0C15AB9218E2A90007494E2 /* Shaders.metal in Sources */,
|
C0C15AB9218E2A90007494E2 /* Shaders.metal in Sources */,
|
||||||
C0C15AB5218E2A90007494E2 /* GameViewController.swift in Sources */,
|
C0C15AB5218E2A90007494E2 /* GameViewController.swift in Sources */,
|
||||||
|
C0C15AC6218E32B3007494E2 /* Terrain.swift in Sources */,
|
||||||
C0C15AB7218E2A90007494E2 /* Renderer.swift in Sources */,
|
C0C15AB7218E2A90007494E2 /* Renderer.swift in Sources */,
|
||||||
C0C15AB3218E2A90007494E2 /* AppDelegate.swift in Sources */,
|
C0C15AB3218E2A90007494E2 /* AppDelegate.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ class Renderer: NSObject, MTKViewDelegate {
|
||||||
|
|
||||||
var rotation: Float = 0
|
var rotation: Float = 0
|
||||||
|
|
||||||
var mesh: MTKMesh
|
var terrain: Terrain
|
||||||
|
|
||||||
init?(metalKitView: MTKView) {
|
init?(metalKitView: MTKView) {
|
||||||
self.device = metalKitView.device!
|
self.device = metalKitView.device!
|
||||||
|
|
@ -61,12 +61,12 @@ class Renderer: NSObject, MTKViewDelegate {
|
||||||
metalKitView.colorPixelFormat = MTLPixelFormat.bgra8Unorm_srgb
|
metalKitView.colorPixelFormat = MTLPixelFormat.bgra8Unorm_srgb
|
||||||
metalKitView.sampleCount = 1
|
metalKitView.sampleCount = 1
|
||||||
|
|
||||||
let mtlVertexDescriptor = Renderer.buildMetalVertexDescriptor()
|
terrain = Terrain(dimensions: float2(8, 8), segments: uint2(20, 20), device: device)!
|
||||||
|
|
||||||
do {
|
do {
|
||||||
pipelineState = try Renderer.buildRenderPipelineWithDevice(device: device,
|
pipelineState = try Renderer.buildRenderPipelineWithDevice(device: device,
|
||||||
metalKitView: metalKitView,
|
metalKitView: metalKitView,
|
||||||
mtlVertexDescriptor: mtlVertexDescriptor)
|
mtlVertexDescriptor: terrain.vertexDescriptor)
|
||||||
} catch {
|
} catch {
|
||||||
print("Unable to compile render pipeline state. Error info: \(error)")
|
print("Unable to compile render pipeline state. Error info: \(error)")
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -77,13 +77,6 @@ class Renderer: NSObject, MTKViewDelegate {
|
||||||
depthStateDesciptor.isDepthWriteEnabled = true
|
depthStateDesciptor.isDepthWriteEnabled = true
|
||||||
self.depthState = device.makeDepthStencilState(descriptor:depthStateDesciptor)!
|
self.depthState = device.makeDepthStencilState(descriptor:depthStateDesciptor)!
|
||||||
|
|
||||||
do {
|
|
||||||
mesh = try Renderer.buildMesh(device: device, mtlVertexDescriptor: mtlVertexDescriptor)
|
|
||||||
} catch {
|
|
||||||
print("Unable to build MetalKit Mesh. Error info: \(error)")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
colorMap = try Renderer.loadTexture(device: device, textureName: "ColorMap")
|
colorMap = try Renderer.loadTexture(device: device, textureName: "ColorMap")
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -95,31 +88,6 @@ class Renderer: NSObject, MTKViewDelegate {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class func buildMetalVertexDescriptor() -> MTLVertexDescriptor {
|
|
||||||
// Creete a Metal vertex descriptor specifying how vertices will by laid out for input into our render
|
|
||||||
// pipeline and how we'll layout our Model IO vertices
|
|
||||||
|
|
||||||
let mtlVertexDescriptor = MTLVertexDescriptor()
|
|
||||||
|
|
||||||
mtlVertexDescriptor.attributes[VertexAttribute.position.rawValue].format = MTLVertexFormat.float3
|
|
||||||
mtlVertexDescriptor.attributes[VertexAttribute.position.rawValue].offset = 0
|
|
||||||
mtlVertexDescriptor.attributes[VertexAttribute.position.rawValue].bufferIndex = BufferIndex.meshPositions.rawValue
|
|
||||||
|
|
||||||
mtlVertexDescriptor.attributes[VertexAttribute.texcoord.rawValue].format = MTLVertexFormat.float2
|
|
||||||
mtlVertexDescriptor.attributes[VertexAttribute.texcoord.rawValue].offset = 0
|
|
||||||
mtlVertexDescriptor.attributes[VertexAttribute.texcoord.rawValue].bufferIndex = BufferIndex.meshGenerics.rawValue
|
|
||||||
|
|
||||||
mtlVertexDescriptor.layouts[BufferIndex.meshPositions.rawValue].stride = 12
|
|
||||||
mtlVertexDescriptor.layouts[BufferIndex.meshPositions.rawValue].stepRate = 1
|
|
||||||
mtlVertexDescriptor.layouts[BufferIndex.meshPositions.rawValue].stepFunction = MTLVertexStepFunction.perVertex
|
|
||||||
|
|
||||||
mtlVertexDescriptor.layouts[BufferIndex.meshGenerics.rawValue].stride = 8
|
|
||||||
mtlVertexDescriptor.layouts[BufferIndex.meshGenerics.rawValue].stepRate = 1
|
|
||||||
mtlVertexDescriptor.layouts[BufferIndex.meshGenerics.rawValue].stepFunction = MTLVertexStepFunction.perVertex
|
|
||||||
|
|
||||||
return mtlVertexDescriptor
|
|
||||||
}
|
|
||||||
|
|
||||||
class func buildRenderPipelineWithDevice(device: MTLDevice,
|
class func buildRenderPipelineWithDevice(device: MTLDevice,
|
||||||
metalKitView: MTKView,
|
metalKitView: MTKView,
|
||||||
mtlVertexDescriptor: MTLVertexDescriptor) throws -> MTLRenderPipelineState {
|
mtlVertexDescriptor: MTLVertexDescriptor) throws -> MTLRenderPipelineState {
|
||||||
|
|
@ -144,30 +112,6 @@ class Renderer: NSObject, MTKViewDelegate {
|
||||||
return try device.makeRenderPipelineState(descriptor: pipelineDescriptor)
|
return try device.makeRenderPipelineState(descriptor: pipelineDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
class func buildMesh(device: MTLDevice,
|
|
||||||
mtlVertexDescriptor: MTLVertexDescriptor) throws -> MTKMesh {
|
|
||||||
/// Create and condition mesh data to feed into a pipeline using the given vertex descriptor
|
|
||||||
|
|
||||||
let metalAllocator = MTKMeshBufferAllocator(device: device)
|
|
||||||
|
|
||||||
let plane = MDLMesh.newPlane(withDimensions: float2(6, 6),
|
|
||||||
segments: uint2(20, 20),
|
|
||||||
geometryType: .triangles,
|
|
||||||
allocator: metalAllocator)
|
|
||||||
|
|
||||||
let mdlVertexDescriptor = MTKModelIOVertexDescriptorFromMetal(mtlVertexDescriptor)
|
|
||||||
|
|
||||||
guard let attributes = mdlVertexDescriptor.attributes as? [MDLVertexAttribute] else {
|
|
||||||
throw RendererError.badVertexDescriptor
|
|
||||||
}
|
|
||||||
attributes[VertexAttribute.position.rawValue].name = MDLVertexAttributePosition
|
|
||||||
attributes[VertexAttribute.texcoord.rawValue].name = MDLVertexAttributeTextureCoordinate
|
|
||||||
|
|
||||||
plane.vertexDescriptor = mdlVertexDescriptor
|
|
||||||
|
|
||||||
return try MTKMesh(mesh:plane, device:device)
|
|
||||||
}
|
|
||||||
|
|
||||||
class func loadTexture(device: MTLDevice,
|
class func loadTexture(device: MTLDevice,
|
||||||
textureName: String) throws -> MTLTexture {
|
textureName: String) throws -> MTLTexture {
|
||||||
/// Load texture data with optimal parameters for sampling
|
/// Load texture data with optimal parameters for sampling
|
||||||
|
|
@ -248,20 +192,20 @@ class Renderer: NSObject, MTKViewDelegate {
|
||||||
renderEncoder.setVertexBuffer(dynamicUniformBuffer, offset:uniformBufferOffset, index: BufferIndex.uniforms.rawValue)
|
renderEncoder.setVertexBuffer(dynamicUniformBuffer, offset:uniformBufferOffset, index: BufferIndex.uniforms.rawValue)
|
||||||
renderEncoder.setFragmentBuffer(dynamicUniformBuffer, offset:uniformBufferOffset, index: BufferIndex.uniforms.rawValue)
|
renderEncoder.setFragmentBuffer(dynamicUniformBuffer, offset:uniformBufferOffset, index: BufferIndex.uniforms.rawValue)
|
||||||
|
|
||||||
for (index, element) in mesh.vertexDescriptor.layouts.enumerated() {
|
for (index, element) in terrain.mesh.vertexDescriptor.layouts.enumerated() {
|
||||||
guard let layout = element as? MDLVertexBufferLayout else {
|
guard let layout = element as? MDLVertexBufferLayout else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.stride != 0 {
|
if layout.stride != 0 {
|
||||||
let buffer = mesh.vertexBuffers[index]
|
let buffer = terrain.mesh.vertexBuffers[index]
|
||||||
renderEncoder.setVertexBuffer(buffer.buffer, offset:buffer.offset, index: index)
|
renderEncoder.setVertexBuffer(buffer.buffer, offset:buffer.offset, index: index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderEncoder.setFragmentTexture(colorMap, index: TextureIndex.color.rawValue)
|
renderEncoder.setFragmentTexture(colorMap, index: TextureIndex.color.rawValue)
|
||||||
|
|
||||||
for submesh in mesh.submeshes {
|
for submesh in terrain.mesh.submeshes {
|
||||||
renderEncoder.drawIndexedPrimitives(type: submesh.primitiveType,
|
renderEncoder.drawIndexedPrimitives(type: submesh.primitiveType,
|
||||||
indexCount: submesh.indexCount,
|
indexCount: submesh.indexCount,
|
||||||
indexType: submesh.indexType,
|
indexType: submesh.indexType,
|
||||||
|
|
|
||||||
79
Terrain2/Terrain.swift
Normal file
79
Terrain2/Terrain.swift
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
//
|
||||||
|
// Terrain.swift
|
||||||
|
// Terrain
|
||||||
|
//
|
||||||
|
// Created by Eryn Wells on 11/3/18.
|
||||||
|
// Copyright © 2018 Eryn Wells. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
import MetalKit
|
||||||
|
|
||||||
|
class Terrain: NSObject {
|
||||||
|
|
||||||
|
/// Creete a Metal vertex descriptor specifying how vertices will by laid out for input into our render pipeline and how we'll layout our Model IO vertices.
|
||||||
|
class func buildVertexDescriptor() -> MTLVertexDescriptor {
|
||||||
|
let mtlVertexDescriptor = MTLVertexDescriptor()
|
||||||
|
|
||||||
|
mtlVertexDescriptor.attributes[VertexAttribute.position.rawValue].format = MTLVertexFormat.float3
|
||||||
|
mtlVertexDescriptor.attributes[VertexAttribute.position.rawValue].offset = 0
|
||||||
|
mtlVertexDescriptor.attributes[VertexAttribute.position.rawValue].bufferIndex = BufferIndex.meshPositions.rawValue
|
||||||
|
|
||||||
|
mtlVertexDescriptor.attributes[VertexAttribute.texcoord.rawValue].format = MTLVertexFormat.float2
|
||||||
|
mtlVertexDescriptor.attributes[VertexAttribute.texcoord.rawValue].offset = 0
|
||||||
|
mtlVertexDescriptor.attributes[VertexAttribute.texcoord.rawValue].bufferIndex = BufferIndex.meshGenerics.rawValue
|
||||||
|
|
||||||
|
mtlVertexDescriptor.layouts[BufferIndex.meshPositions.rawValue].stride = 12
|
||||||
|
mtlVertexDescriptor.layouts[BufferIndex.meshPositions.rawValue].stepRate = 1
|
||||||
|
mtlVertexDescriptor.layouts[BufferIndex.meshPositions.rawValue].stepFunction = MTLVertexStepFunction.perVertex
|
||||||
|
|
||||||
|
mtlVertexDescriptor.layouts[BufferIndex.meshGenerics.rawValue].stride = 8
|
||||||
|
mtlVertexDescriptor.layouts[BufferIndex.meshGenerics.rawValue].stepRate = 1
|
||||||
|
mtlVertexDescriptor.layouts[BufferIndex.meshGenerics.rawValue].stepFunction = MTLVertexStepFunction.perVertex
|
||||||
|
|
||||||
|
return mtlVertexDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create and condition mesh data to feed into a pipeline using the given vertex descriptor.
|
||||||
|
class func buildMesh(withDimensions dimensions: float2, segments: uint2, device: MTLDevice, vertexDescriptor: MTLVertexDescriptor) throws -> MTKMesh {
|
||||||
|
let metalAllocator = MTKMeshBufferAllocator(device: device)
|
||||||
|
|
||||||
|
let plane = MDLMesh.newPlane(withDimensions: dimensions,
|
||||||
|
segments: segments,
|
||||||
|
geometryType: .triangles,
|
||||||
|
allocator: metalAllocator)
|
||||||
|
|
||||||
|
let mdlVertexDescriptor = MTKModelIOVertexDescriptorFromMetal(vertexDescriptor)
|
||||||
|
|
||||||
|
guard let attributes = mdlVertexDescriptor.attributes as? [MDLVertexAttribute] else {
|
||||||
|
throw RendererError.badVertexDescriptor
|
||||||
|
}
|
||||||
|
attributes[VertexAttribute.position.rawValue].name = MDLVertexAttributePosition
|
||||||
|
attributes[VertexAttribute.texcoord.rawValue].name = MDLVertexAttributeTextureCoordinate
|
||||||
|
|
||||||
|
plane.vertexDescriptor = mdlVertexDescriptor
|
||||||
|
|
||||||
|
return try MTKMesh(mesh:plane, device:device)
|
||||||
|
}
|
||||||
|
|
||||||
|
let dimensions: float2
|
||||||
|
let segments: uint2
|
||||||
|
|
||||||
|
let vertexDescriptor: MTLVertexDescriptor
|
||||||
|
let mesh: MTKMesh
|
||||||
|
|
||||||
|
init?(dimensions dim: float2, segments seg: uint2, device: MTLDevice) {
|
||||||
|
dimensions = dim
|
||||||
|
segments = seg
|
||||||
|
vertexDescriptor = Terrain.buildVertexDescriptor()
|
||||||
|
|
||||||
|
do {
|
||||||
|
mesh = try Terrain.buildMesh(withDimensions: dimensions, segments: segments, device: device, vertexDescriptor: vertexDescriptor)
|
||||||
|
} catch let e {
|
||||||
|
print("Couldn't create mesh. Error: \(e)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue