renderEncoder?.drawIndexedPrimitives(type: .line…

Hello Everyone, within the renderEncoder?.drawIndexedPrimitives(type: .line…. function, I can't render all the lines of the object. I can see approx. 80%. Do you know what could be causing this? Other game engines, like those in C++, handle this just fine.

import MetalKit

class Renderer: NSObject, MTKViewDelegate {

var parent: ContentView
var metalDevice: MTLDevice!
var metalCommandQueue: MTLCommandQueue!

let allocator: MTKMeshBufferAllocator

let pipelineState: MTLRenderPipelineState
var scene: RenderScene
let mesh: ObjMesh

init(_ parent: ContentView) {
    
    self.parent = parent
    if let metalDevice = MTLCreateSystemDefaultDevice() {
        self.metalDevice = metalDevice
    }
    self.metalCommandQueue = metalDevice.makeCommandQueue()
    
    self.allocator = MTKMeshBufferAllocator(device: metalDevice)
    
    mesh = ObjMesh(device: metalDevice, allocator: allocator, filename: "cube")
    
    let pipelineDescriptor = MTLRenderPipelineDescriptor()
    let library = metalDevice.makeDefaultLibrary()
    pipelineDescriptor.vertexFunction = library?.makeFunction(name: "vertexShader")
    pipelineDescriptor.fragmentFunction = library?.makeFunction(name: "fragmentShader")
    pipelineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
    pipelineDescriptor.vertexDescriptor = MTKMetalVertexDescriptorFromModelIO(mesh.metalMesh.vertexDescriptor)
    
    do {
        try pipelineState = metalDevice.makeRenderPipelineState(descriptor: pipelineDescriptor)
    } catch {
        fatalError()
    }
    
    scene = RenderScene()
    
    super.init()
}

func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
    
}

func draw(in view: MTKView) {
    
    //update
    scene.update()
    
    guard let drawable = view.currentDrawable else {
        return
    }
    
    let commandBuffer = metalCommandQueue.makeCommandBuffer()
    
    let renderPassDescriptor = view.currentRenderPassDescriptor
    renderPassDescriptor?.colorAttachments[0].clearColor = MTLClearColorMake(0, 0.5, 0.5, 1.0)
    renderPassDescriptor?.colorAttachments[0].loadAction = .clear
    renderPassDescriptor?.colorAttachments[0].storeAction = .store
    
    let renderEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor: renderPassDescriptor!)
    renderEncoder?.setRenderPipelineState(pipelineState)
    
    var cameraData: CameraParameters = CameraParameters()
    cameraData.view = Matrix44.create_lookat(
        eye: scene.player.position,
        target: scene.player.position + scene.player.forwards,
        up: scene.player.up
    )
    cameraData.projection = Matrix44.create_perspective_projection(
        fovy: 45, aspect: 800/600, near: 0.1, far: 10
    )
    renderEncoder?.setVertexBytes(&cameraData, length: MemoryLayout<CameraParameters>.stride, index: 2)
    
    renderEncoder?.setVertexBuffer(mesh.metalMesh.vertexBuffers[0].buffer, offset: 0, index: 0)
    for cube in scene.cubes {
        
        var model: matrix_float4x4 = Matrix44.create_from_rotation(eulers: cube.eulers)
        model = Matrix44.create_from_translation(translation: cube.position) * model
        renderEncoder?.setVertexBytes(&model, length: MemoryLayout<matrix_float4x4>.stride, index: 1)
        
        for submesh in mesh.metalMesh.submeshes {
            renderEncoder?.drawIndexedPrimitives(
                type: .line, indexCount: submesh.indexCount,
                indexType: submesh.indexType, indexBuffer: submesh.indexBuffer.buffer,
                indexBufferOffset: submesh.indexBuffer.offset
            )
        }
    }
    
    renderEncoder?.endEncoding()
    
    commandBuffer?.present(drawable)
    commandBuffer?.commit()
}

}

====================

import MetalKit

class ObjMesh {

let modelIOMesh: MDLMesh
let metalMesh: MTKMesh

init(device: MTLDevice, allocator: MTKMeshBufferAllocator, filename: String) {
    guard let meshURL = Bundle.main.url(forResource: filename, withExtension: "obj") else {
        fatalError()
    }
    let vertexDescriptor = MTLVertexDescriptor()
    
    var offset: Int = 0
    
    //position
    vertexDescriptor.attributes[0].format = .float3
    vertexDescriptor.attributes[0].offset = offset
    vertexDescriptor.attributes[0].bufferIndex = 0
    offset += MemoryLayout<SIMD3<Float>>.stride
    
    vertexDescriptor.layouts[0].stride = offset
    
    let meshDescriptor = MTKModelIOVertexDescriptorFromMetal(vertexDescriptor)
    (meshDescriptor.attributes[0] as! MDLVertexAttribute).name = MDLVertexAttributePosition
    let asset = MDLAsset(url: meshURL,
                         vertexDescriptor: meshDescriptor,
                         bufferAllocator: allocator)
    self.modelIOMesh = asset.childObjects(of: MDLMesh.self).first as! MDLMesh
    do {
        metalMesh = try MTKMesh(mesh: self.modelIOMesh, device: device)
    } catch {
        fatalError("couldn't load mesh")
    }
}

}

===============

cube.obj

Blender v2.91.0 OBJ File: ''

www_blender_org

mtllib piece.mtl o Cube_Cube.001 v -1.000000 1.000000 -1.000000 v -1.000000 1.000000 1.000000 v 1.000000 1.000000 -1.000000 v 1.000000 1.000000 1.000000 v -1.000000 -1.000000 -1.000000 v -1.000000 -1.000000 1.000000 v 1.000000 -1.000000 -1.000000 v 1.000000 -1.000000 1.000000 vt 0.375000 0.000000 vt 0.625000 0.000000 vt 0.625000 0.250000 vt 0.375000 0.250000 vt 0.625000 0.500000 vt 0.375000 0.500000 vt 0.625000 0.750000 vt 0.375000 0.750000 vt 0.625000 1.000000 vt 0.375000 1.000000 vt 0.125000 0.500000 vt 0.125000 0.750000 vt 0.875000 0.500000 vt 0.875000 0.750000 vn 0.0000 1.0000 0.0000 vn 1.0000 0.0000 0.0000 vn 0.0000 -1.0000 0.0000 vn -1.0000 0.0000 0.0000 vn 0.0000 0.0000 -1.0000 vn 0.0000 0.0000 1.0000 usemtl None s off f 1/1/1 2/2/1 4/3/1 3/4/1 f 3/4/2 4/3/2 8/5/2 7/6/2 f 7/6/3 8/5/3 6/7/3 5/8/3 f 5/8/4 6/7/4 2/9/4 1/10/4 f 3/11/5 7/6/5 5/8/5 1/12/5 f 8/5/6 4/13/6 2/14/6 6/7/6

Answered by milanmach2 in 809832022

So even Swift 6, Xcode 16 did not help. it seems to be a bug within the original code. The function is not working as expected. I would like to ask to solve the bug by the function: renderEncoder?.drawPrimitives(type: .line, vertexStart: 0, vertexCount: 3) and renderEncoder?.drawPrimitives(type: .lineStrip, vertexStart: 0, vertexCount: 3)

I don’t see anything obviously wrong with your code. Depending on the size of your scene and how things are positioned, it could be an issue with your projection matrix’s “far” distance being too close, which would cause anything beyond (currently) 10 units to get clipped away. Can you share a screenshot of what “80%” looks like? Does it change as you move the camera?

Hi Noah-w, Thanks for your reply. Actually, the issue has nothing to do with the camera or z-far. For example, when I use renderEncoder?.drawIndexedPrimitives(type: .triangle...), the rendering is perfect, and even the areas that weren't correct in .line mode are displayed properly. The cube rotates as expected. However, in line mode, if a line isn’t rendered, it remains missing throughout the entire rotation of the cube, even when it falls within the z-near and z-far range.

Accepted Answer

So even Swift 6, Xcode 16 did not help. it seems to be a bug within the original code. The function is not working as expected. I would like to ask to solve the bug by the function: renderEncoder?.drawPrimitives(type: .line, vertexStart: 0, vertexCount: 3) and renderEncoder?.drawPrimitives(type: .lineStrip, vertexStart: 0, vertexCount: 3)

renderEncoder?.drawIndexedPrimitives(type: .line…
 
 
Q