iOS Metal - 渲染一个完整的三角形
iOS Metal - rendering a complete triangle
我正在尝试 https://www.raywenderlich.com/81399/ios-8-metal-tutorial-swift-moving-to-3d
的 Metal 教程
此问题仅与教程的第一部分有关,其中先渲染三角形,然后渲染立方体。
我似乎已经完成了提到的所有事情,创建了一个顶点结构,节点class,三角形(然后是立方体子class),重构了我的视图控制器和着色器。
应用呈现,但它只呈现一半屏幕,如下所示:
这是我的 ViewController:
import UIKit
import Metal
import QuartzCore
class ViewController: UIViewController {
var device : MTLDevice! = nil
var metalLayer : CAMetalLayer! = nil
var vertexBuffer : MTLBuffer! = nil
var pipelineState : MTLRenderPipelineState! = nil
var commandQueue: MTLCommandQueue! = nil
var timer: CADisplayLink! = nil
var objectToDraw: Triangle!
override func viewDidLoad() {
super.viewDidLoad()
initialize_2()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func initialize_2(){
device = MTLCreateSystemDefaultDevice()
metalLayer = CAMetalLayer()
metalLayer.device = device
metalLayer.pixelFormat = .BGRA8Unorm
metalLayer.framebufferOnly = true
metalLayer.frame = view.layer.frame
view.layer.addSublayer(metalLayer)
objectToDraw = Triangle(device: device)
let defaultLibrary = device.newDefaultLibrary()
let fragmentProgram = defaultLibrary!.newFunctionWithName("basic_fragment")
let vertexProgram = defaultLibrary!.newFunctionWithName("basic_vertex")
let pipelineStateDescriptor = MTLRenderPipelineDescriptor()
pipelineStateDescriptor.vertexFunction = vertexProgram
pipelineStateDescriptor.fragmentFunction = fragmentProgram
pipelineStateDescriptor.colorAttachments[0].pixelFormat = .BGRA8Unorm
do{
try pipelineState = device.newRenderPipelineStateWithDescriptor(pipelineStateDescriptor)
}catch is NSError{
print("Failed to create pipeline state")
}
commandQueue = device.newCommandQueue()
timer = CADisplayLink(target: self, selector: #selector(ViewController.gameloop_2))
timer.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSDefaultRunLoopMode)
}
func gameloop_2() {
autoreleasepool {
self.render_2()
}
}
func render_2(){
var drawable = metalLayer.nextDrawable()
objectToDraw.render(commandQueue, pipelineState: pipelineState, drawable: drawable!, clearColor: nil)
}
}
这是我的顶点 class:
import Foundation
struct Vertex{
var x, y, z : Float // position data
var r, g, b, a : Float // color data
func floatBuffer() -> [Float]{
return [x,y,x,r,g,b,a]
}
}
节点class:
import Foundation
import Metal
import QuartzCore
class Node {
let name: String
var vertexCount: Int
var vertexBuffer: MTLBuffer
var device: MTLDevice
init(name: String, vertices: Array<Vertex>, device: MTLDevice){
// 1
var vertexData = Array<Float>()
for vertex in vertices{
vertexData += vertex.floatBuffer()
}
// 2
let dataSize = vertexData.count * sizeofValue(vertexData[0])
vertexBuffer = device.newBufferWithBytes(vertexData, length: dataSize, options: [])
// 3
self.name = name
self.device = device
vertexCount = vertices.count
}
func render(commandQueue: MTLCommandQueue, pipelineState: MTLRenderPipelineState, drawable: CAMetalDrawable, clearColor: MTLClearColor?){
let renderPassDescriptor = MTLRenderPassDescriptor()
renderPassDescriptor.colorAttachments[0].texture = drawable.texture
renderPassDescriptor.colorAttachments[0].loadAction = .Clear
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red: 0.0, green: 104.0/255.0, blue: 5.0/255.0, alpha: 1.0)
renderPassDescriptor.colorAttachments[0].storeAction = .Store
let commandBuffer = commandQueue.commandBuffer()
let renderEncoderOpt : MTLRenderCommandEncoder! = commandBuffer.renderCommandEncoderWithDescriptor(renderPassDescriptor)
if let renderEncoder = renderEncoderOpt {
renderEncoder.setRenderPipelineState(pipelineState)
renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, atIndex: 0)
renderEncoder.drawPrimitives(.Triangle, vertexStart: 0, vertexCount: vertexCount, instanceCount: vertexCount/3)
renderEncoder.endEncoding()
}
commandBuffer.presentDrawable(drawable)
commandBuffer.commit()
}
}
和三角形class:
import Foundation
import Metal
class Triangle: Node {
init(device: MTLDevice){
let V0 = Vertex(x: 0.0, y: 1.0, z: 0.0, r: 1.0, g: 0.0, b: 0.0, a: 1.0)
let V1 = Vertex(x: -1.0, y: -1.0, z: 0.0, r: 0.0, g: 1.0, b: 0.0, a: 1.0)
let V2 = Vertex(x: 1.0, y: -1.0, z: 0.0, r: 0.0, g: 0.0, b: 1.0, a: 1.0)
var verticesArray = [V0,V1,V2]
super.init(name: "Triangle", vertices: verticesArray, device: device)
}
}
我的着色器文件:
#include <metal_stdlib>
using namespace metal;
struct VertexIn{
packed_float3 position;
packed_float4 color;
};
struct VertexOut{
float4 position [[position]];
float4 color;
};
vertex VertexOut basic_vertex(
const device VertexIn* vertex_array [[ buffer(0) ]],
unsigned int vid [[ vertex_id ]]) {
VertexIn VertexIn = vertex_array[vid];
VertexOut VertexOut;
VertexOut.position = float4(VertexIn.position,1);
VertexOut.color = VertexIn.color;
return VertexOut;
}
fragment half4 basic_fragment(VertexOut interpolated [[stage_in]]) {
return half4(interpolated.color[0], interpolated.color[1], interpolated.color[2], interpolated.color[3]);
}
我想了解为什么着色器不渲染完整的三角形。我对图形编程也(非常)陌生,因此非常感谢任何帮助或指导。教程的 link 再次是:https://www.raywenderlich.com/81399/ios-8-metal-tutorial-swift-moving-to-3d
编辑:我正在 运行 播出 iPad 节目,如果这会有什么不同的话。我也尝试更改 Triangle.swift 中的坐标,但显然我做错了。
我发现顶点设置中有一个小错误可能会导致此问题。
func floatBuffer() -> [Float]{
return [x,y,x,r,g,b,a]
}
我正在尝试 https://www.raywenderlich.com/81399/ios-8-metal-tutorial-swift-moving-to-3d
的 Metal 教程此问题仅与教程的第一部分有关,其中先渲染三角形,然后渲染立方体。
我似乎已经完成了提到的所有事情,创建了一个顶点结构,节点class,三角形(然后是立方体子class),重构了我的视图控制器和着色器。
应用呈现,但它只呈现一半屏幕,如下所示:
这是我的 ViewController:
import UIKit
import Metal
import QuartzCore
class ViewController: UIViewController {
var device : MTLDevice! = nil
var metalLayer : CAMetalLayer! = nil
var vertexBuffer : MTLBuffer! = nil
var pipelineState : MTLRenderPipelineState! = nil
var commandQueue: MTLCommandQueue! = nil
var timer: CADisplayLink! = nil
var objectToDraw: Triangle!
override func viewDidLoad() {
super.viewDidLoad()
initialize_2()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func initialize_2(){
device = MTLCreateSystemDefaultDevice()
metalLayer = CAMetalLayer()
metalLayer.device = device
metalLayer.pixelFormat = .BGRA8Unorm
metalLayer.framebufferOnly = true
metalLayer.frame = view.layer.frame
view.layer.addSublayer(metalLayer)
objectToDraw = Triangle(device: device)
let defaultLibrary = device.newDefaultLibrary()
let fragmentProgram = defaultLibrary!.newFunctionWithName("basic_fragment")
let vertexProgram = defaultLibrary!.newFunctionWithName("basic_vertex")
let pipelineStateDescriptor = MTLRenderPipelineDescriptor()
pipelineStateDescriptor.vertexFunction = vertexProgram
pipelineStateDescriptor.fragmentFunction = fragmentProgram
pipelineStateDescriptor.colorAttachments[0].pixelFormat = .BGRA8Unorm
do{
try pipelineState = device.newRenderPipelineStateWithDescriptor(pipelineStateDescriptor)
}catch is NSError{
print("Failed to create pipeline state")
}
commandQueue = device.newCommandQueue()
timer = CADisplayLink(target: self, selector: #selector(ViewController.gameloop_2))
timer.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSDefaultRunLoopMode)
}
func gameloop_2() {
autoreleasepool {
self.render_2()
}
}
func render_2(){
var drawable = metalLayer.nextDrawable()
objectToDraw.render(commandQueue, pipelineState: pipelineState, drawable: drawable!, clearColor: nil)
}
}
这是我的顶点 class:
import Foundation
struct Vertex{
var x, y, z : Float // position data
var r, g, b, a : Float // color data
func floatBuffer() -> [Float]{
return [x,y,x,r,g,b,a]
}
}
节点class:
import Foundation
import Metal
import QuartzCore
class Node {
let name: String
var vertexCount: Int
var vertexBuffer: MTLBuffer
var device: MTLDevice
init(name: String, vertices: Array<Vertex>, device: MTLDevice){
// 1
var vertexData = Array<Float>()
for vertex in vertices{
vertexData += vertex.floatBuffer()
}
// 2
let dataSize = vertexData.count * sizeofValue(vertexData[0])
vertexBuffer = device.newBufferWithBytes(vertexData, length: dataSize, options: [])
// 3
self.name = name
self.device = device
vertexCount = vertices.count
}
func render(commandQueue: MTLCommandQueue, pipelineState: MTLRenderPipelineState, drawable: CAMetalDrawable, clearColor: MTLClearColor?){
let renderPassDescriptor = MTLRenderPassDescriptor()
renderPassDescriptor.colorAttachments[0].texture = drawable.texture
renderPassDescriptor.colorAttachments[0].loadAction = .Clear
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red: 0.0, green: 104.0/255.0, blue: 5.0/255.0, alpha: 1.0)
renderPassDescriptor.colorAttachments[0].storeAction = .Store
let commandBuffer = commandQueue.commandBuffer()
let renderEncoderOpt : MTLRenderCommandEncoder! = commandBuffer.renderCommandEncoderWithDescriptor(renderPassDescriptor)
if let renderEncoder = renderEncoderOpt {
renderEncoder.setRenderPipelineState(pipelineState)
renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, atIndex: 0)
renderEncoder.drawPrimitives(.Triangle, vertexStart: 0, vertexCount: vertexCount, instanceCount: vertexCount/3)
renderEncoder.endEncoding()
}
commandBuffer.presentDrawable(drawable)
commandBuffer.commit()
}
}
和三角形class:
import Foundation
import Metal
class Triangle: Node {
init(device: MTLDevice){
let V0 = Vertex(x: 0.0, y: 1.0, z: 0.0, r: 1.0, g: 0.0, b: 0.0, a: 1.0)
let V1 = Vertex(x: -1.0, y: -1.0, z: 0.0, r: 0.0, g: 1.0, b: 0.0, a: 1.0)
let V2 = Vertex(x: 1.0, y: -1.0, z: 0.0, r: 0.0, g: 0.0, b: 1.0, a: 1.0)
var verticesArray = [V0,V1,V2]
super.init(name: "Triangle", vertices: verticesArray, device: device)
}
}
我的着色器文件:
#include <metal_stdlib>
using namespace metal;
struct VertexIn{
packed_float3 position;
packed_float4 color;
};
struct VertexOut{
float4 position [[position]];
float4 color;
};
vertex VertexOut basic_vertex(
const device VertexIn* vertex_array [[ buffer(0) ]],
unsigned int vid [[ vertex_id ]]) {
VertexIn VertexIn = vertex_array[vid];
VertexOut VertexOut;
VertexOut.position = float4(VertexIn.position,1);
VertexOut.color = VertexIn.color;
return VertexOut;
}
fragment half4 basic_fragment(VertexOut interpolated [[stage_in]]) {
return half4(interpolated.color[0], interpolated.color[1], interpolated.color[2], interpolated.color[3]);
}
我想了解为什么着色器不渲染完整的三角形。我对图形编程也(非常)陌生,因此非常感谢任何帮助或指导。教程的 link 再次是:https://www.raywenderlich.com/81399/ios-8-metal-tutorial-swift-moving-to-3d
编辑:我正在 运行 播出 iPad 节目,如果这会有什么不同的话。我也尝试更改 Triangle.swift 中的坐标,但显然我做错了。
我发现顶点设置中有一个小错误可能会导致此问题。
func floatBuffer() -> [Float]{
return [x,y,x,r,g,b,a]
}