Ich versuche, ein Pixel ausgerichtet 2D Quad mit Metall, aber kann nicht scheinen, es richtig zu machen.Rendering Quad von Vertex Buffer in Metall
My Vertex Pufferinhalt (wie von der CPU-Seite angemeldet, bei der Erzeugung) sind:
Vertex(position: float4(0.0, 0.0, 0.5, 1.0), textureCoordinate: float2(0.0, 0.0))
Vertex(position: float4(0.0, 64.0, 0.5, 1.0), textureCoordinate: float2(0.0, 1.0))
Vertex(position: float4(64.0, 0.0, 0.5, 1.0), textureCoordinate: float2(1.0, 0.0))
Vertex(position: float4(64.0, 64.0, 0.5, 1.0), textureCoordinate: float2(1.0, 1.0))
Indexpuffer zwei Dreiecke enthält die folgenden Indizes zu zeichnen:
0, 1, 2, 2, 1, 3
Die Textur I bin mit ist:
... aber ich habe so etwas wie dies:
Wenn der Rahmen die Erfassung und die Eckpunktpufferspeicher Inspektion, bekomme ich diese:
klar, Position und Texturkoordinaten sind vermischt.
Dies ist der Code, den ich verwende, um die Geometrie zu erstellen:
import Metal
import simd
struct Vertex {
var position = float4(x: 0, y: 0, z: 0, w: 1)
var textureCoordinate = float2(x: 0, y: 0)
}
class Quad {
let vertexBuffer: MTLBuffer
let indexBuffer: MTLBuffer
let indexCount: Int
let indexType: MTLIndexType
let primitiveType: MTLPrimitiveType
init(sideLength: Float, device: MTLDevice) {
self.primitiveType = .triangle
var vertexData = [Vertex]()
var topLeft = Vertex()
topLeft.position.x = 0
topLeft.position.y = 0
topLeft.position.z = 0.5
topLeft.textureCoordinate.x = 0
topLeft.textureCoordinate.y = 0
vertexData.append(topLeft)
var bottomLeft = Vertex()
bottomLeft.position.x = 0
bottomLeft.position.y = sideLength
bottomLeft.position.z = 0.5
bottomLeft.textureCoordinate.x = 0
bottomLeft.textureCoordinate.y = 1
vertexData.append(bottomLeft)
var topRight = Vertex()
topRight.position.x = sideLength
topRight.position.y = 0
topRight.position.z = 0.5
topRight.textureCoordinate.x = 1
topRight.textureCoordinate.y = 0
vertexData.append(topRight)
var bottomRight = Vertex()
bottomRight.position.x = sideLength
bottomRight.position.y = sideLength
bottomRight.position.z = 0.5
bottomRight.textureCoordinate.x = 1
bottomRight.textureCoordinate.y = 1
vertexData.append(bottomRight)
for vertex in vertexData {
Swift.print(vertex) // logs the structs posted above
}
let vertexBufferSize = vertexData.count * MemoryLayout<Vertex>.stride
self.vertexBuffer = device.makeBuffer(bytes: vertexData, length: vertexBufferSize, options: [])
var indexData = [UInt32]()
// First triangle: Top left, bottom left, top right (CCW)
indexData.append(0)
indexData.append(1)
indexData.append(2)
// Second triangle: top right, bottom left, bottom right (CCW)
indexData.append(2)
indexData.append(1)
indexData.append(3)
for index in indexData {
Swift.print(index) // logs the integers posted before
}
self.indexType = .uint32
self.indexCount = indexData.count
let indexBufferSize = indexData.count * MemoryLayout<UInt32>.stride
self.indexBuffer = device.makeBuffer(bytes: indexData, length: indexBufferSize, options: [])
}
}
... die Shaders:
#include <metal_stdlib>
using namespace metal;
struct Constants {
float4x4 modelViewProjectionMatrix;
float4 tintColor;
};
struct VertexIn {
packed_float4 position [[ attribute(0) ]];
packed_float2 texCoords [[ attribute(1) ]];
};
struct VertexOut {
float4 position [[position]];
float2 texCoords;
};
vertex VertexOut sprite_vertex_transform(device VertexIn *vertices [[buffer(0)]],
constant Constants &uniforms [[buffer(1)]],
uint vertexId [[vertex_id]]) {
float4 modelPosition = vertices[vertexId].position;
VertexOut out;
out.position = uniforms.modelViewProjectionMatrix * modelPosition;
out.texCoords = vertices[vertexId].texCoords;
return out;
}
fragment half4 sprite_fragment_textured(
VertexOut fragmentIn [[stage_in]],
texture2d<float, access::sample> tex2d [[texture(0)]],
sampler sampler2d [[sampler(0)]]){
half4 surfaceColor = half4(tex2d.sample(sampler2d, fragmentIn.texCoords).rgba);
return surfaceColor;
}
... und das ist der Code, um es (indexiert) zu machen:
renderEncoder.setVertexBuffer(quad.vertexBuffer, offset: 0, at: 0)
renderEncoder.setVertexBytes(&constants, length: MemoryLayout<Constants>.stride, at: 1)
renderEncoder.setFragmentTexture(texture, at: 0)
renderEncoder.setFragmentSamplerState(sampler, at: 0)
// quad is an instance of the class above, with sideLength == 64
renderEncoder.drawIndexedPrimitives(
type: quad.primitiveType,
indexCount: quad.indexCount,
indexType: quad.indexType,
indexBuffer: quad.indexBuffer,
indexBufferOffset: 0)
Offensichtlich werden die Daten nicht in geeigneter Weise an den Eckenpuffer kopiert werden, und ich bin die Fortschritte falsch irgendwo bekommen, aber ich kann nicht ganz herausfinden, wo.
Das gesamte Projekt ist on GitHub.