iOS Metal

编程入门 行业动态 更新时间:2024-10-21 06:43:40
iOS Metal - 渲染完整的三角形(iOS Metal - rendering a complete triangle)

我正在尝试从金属教程https://www.raywenderlich.com/81399/ios-8-metal-tutorial-swift-moving-to-3d

此问题仅适用于本教程的第一部分,其中呈现三角形和更高版本的立方体。

我似乎完成了所提到的一切,创建了一个顶点结构,节点类,三角形(然后是立方体子类),重构了我的视图控制器和着色器。

该应用程序渲染,但它只渲染到屏幕的一半,如下所示:

这是我的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) } }

这是我的Vertex类:

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] } }

和Node类:

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() } }

而三角类:

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]); }

我试图理解为什么着色器不呈现完整的三角形。 我也是(非常)新的图形编程,所以任何帮助或方向都将是最受欢迎的。 再次指向教程的链接是: https : //www.raywenderlich.com/81399/ios-8-metal-tutorial-swift-moving-to-3d

编辑:我在iPad上播放这个,如果这会有所不同。 我也试过改变Triangle.swift中的坐标,但显然我做错了。

I am trying a tutorial on Metal from https://www.raywenderlich.com/81399/ios-8-metal-tutorial-swift-moving-to-3d

This question only pertains to the first part of the tutorial where a triangle and later a cube are rendered.

I seem to have done everything as mentioned, create a vertex structure, node class, triangle (and then cube subclass), refactored my view controller and shader.

The app renders, however it renders to only half the screen like so:

Here is my 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) } }

Here is my Vertex 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] } }

And the Node 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() } }

And the Triangle 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) } }

And my shader file:

#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]); }

I am trying to understand why the shader does not render a complete triangle. I am also (very) new to graphics programming so any help or direction would be most appreciated. Once again the link to the tutorial is : https://www.raywenderlich.com/81399/ios-8-metal-tutorial-swift-moving-to-3d

Edit: I am running this on an iPad air, if that is going to make any difference. I also tried changing the coordinates in Triangle.swift, but obviously I am doing something wrong.

最满意答案

我可以看到可能导致这种情况的顶点设置中的一个小错误。

func floatBuffer() -> [Float]{ return [x,y,x,r,g,b,a] }

I can see a small mistake in the setting of vertices that could be causing this.

func floatBuffer() -> [Float]{ return [x,y,x,r,g,b,a] }

更多推荐

本文发布于:2023-07-04 11:01:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1023566.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:iOS   Metal

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!