2016-09-07 3 views
1

J'essaye de charger un modèle (forme .OBJ) et le dessine à l'écran sur iOS avec MetalKit. Le problème est qu'au lieu de mon modèle, je reçois des polygones au hasard ... Voici le code qui est tendance à charger le modèle (le code est basé sur un tutoriel de raywenderlich.com:Dessin indexé avec du métal

 let allocator    = MTKMeshBufferAllocator(device: device) 
     let vertexDescriptor  = MDLVertexDescriptor() 
     let vertexLayout   = MDLVertexBufferLayout() 
     vertexLayout.stride   = sizeof(Vertex) 
     vertexDescriptor.layouts = [vertexLayout] 
     vertexDescriptor.attributes = [MDLVertexAttribute(name: MDLVertexAttributePosition, format: MDLVertexFormat.Float3, offset: 0, bufferIndex: 0), 
             MDLVertexAttribute(name: MDLVertexAttributeColor, format: MDLVertexFormat.Float4, offset: sizeof(float3), bufferIndex: 0), 
             MDLVertexAttribute(name: MDLVertexAttributeTextureCoordinate, format: MDLVertexFormat.Float2, offset: sizeof(float3)+sizeof(float4), bufferIndex: 0), 
             MDLVertexAttribute(name: MDLVertexAttributeNormal, format: MDLVertexFormat.Float3, offset: sizeof(float3)+sizeof(float4)+sizeof(float2), bufferIndex: 0)] 
     var error: NSError? 
     let asset = MDLAsset(URL: path, vertexDescriptor: vertexDescriptor, bufferAllocator: allocator, preserveTopology: true, error: &error) 
     if error != nil{ 
      print(error) 
      return nil 
     } 

     let model = asset.objectAtIndex(0) as! MDLMesh 
     let mesh = try MTKMesh(mesh: model, device: device) 

Et voici ma méthode de dessin:

func render(commandQueue: MTLCommandQueue, pipelineState: MTLRenderPipelineState,drawable: CAMetalDrawable,projectionMatrix: float4x4,modelViewMatrix: float4x4, clearColor: MTLClearColor){ 

    dispatch_semaphore_wait(bufferProvider.availibleResourcesSemaphore, DISPATCH_TIME_FOREVER) 

    let renderPassDescriptor = MTLRenderPassDescriptor() 
    renderPassDescriptor.colorAttachments[0].texture = drawable.texture 
    renderPassDescriptor.colorAttachments[0].loadAction = .Clear 
    renderPassDescriptor.colorAttachments[0].clearColor = clearColor 
    renderPassDescriptor.colorAttachments[0].storeAction = .Store 

    let commandBuffer = commandQueue.commandBuffer() 
    commandBuffer.addCompletedHandler { (buffer) in 
     dispatch_semaphore_signal(self.bufferProvider.availibleResourcesSemaphore) 
    } 

    let renderEncoder = commandBuffer.renderCommandEncoderWithDescriptor(renderPassDescriptor) 
    renderEncoder.setCullMode(MTLCullMode.None) 

    renderEncoder.setRenderPipelineState(pipelineState) 
    renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, atIndex: 0) 
    renderEncoder.setFragmentTexture(texture, atIndex: 0) 
    if let samplerState = samplerState{ 
     renderEncoder.setFragmentSamplerState(samplerState, atIndex: 0) 
    } 


    var nodeModelMatrix = self.modelMatrix() 
    nodeModelMatrix.multiplyLeft(modelViewMatrix) 
    uniformBuffer = bufferProvider.nextUniformsBuffer(projectionMatrix, modelViewMatrix: nodeModelMatrix, light: light) 
    renderEncoder.setVertexBuffer(self.uniformBuffer, offset: 0, atIndex: 1) 
    renderEncoder.setFragmentBuffer(uniformBuffer, offset: 0, atIndex: 1) 
    if indexBuffer != nil{ 
     renderEncoder.drawIndexedPrimitives(.Triangle, indexCount: self.indexCount, indexType: self.indexType, indexBuffer: self.indexBuffer!, indexBufferOffset: 0) 
    }else{ 
     renderEncoder.drawPrimitives(.Triangle, vertexStart: 0, vertexCount: vertexCount, instanceCount: vertexCount/3) 
    } 
    renderEncoder.endEncoding() 

    commandBuffer.presentDrawable(drawable) 
    commandBuffer.commit() 
} 

Voici mon vertex shader:

struct VertexIn{ 
    packed_float3 position; 
    packed_float4 color; 
    packed_float2 texCoord; 
    packed_float3 normal; 
}; 

struct VertexOut{ 
    float4 position [[position]]; 
    float3 fragmentPosition; 
    float4 color; 
    float2 texCoord; 
    float3 normal; 
}; 

struct Light{ 
    packed_float3 color; 
    float ambientIntensity; 
    packed_float3 direction; 
    float diffuseIntensity; 
    float shininess; 
    float specularIntensity; 
}; 

struct Uniforms{ 
    float4x4 modelMatrix; 
    float4x4 projectionMatrix; 
    Light light; 
}; 

vertex VertexOut basic_vertex(
          const device VertexIn* vertex_array [[ buffer(0) ]], 
          const device Uniforms& uniforms [[ buffer(1) ]], 
          unsigned int vid [[ vertex_id ]]) { 

    float4x4 mv_Matrix = uniforms.modelMatrix; 
    float4x4 proj_Matrix = uniforms.projectionMatrix; 

    VertexIn VertexIn = vertex_array[vid]; 

    VertexOut VertexOut; 
    VertexOut.position = proj_Matrix * mv_Matrix * float4(VertexIn.position,1); 
    VertexOut.fragmentPosition = (mv_Matrix * float4(VertexIn.position,1)).xyz; 
    VertexOut.color = VertexIn.color; 
    VertexOut.texCoord = VertexIn.texCoord; 
    VertexOut.normal = (mv_Matrix * float4(VertexIn.normal, 0.0)).xyz; 
    return VertexOut; 
} 

Et voici à quoi ça ressemble:

link

En fait, j'ai une autre classe qui est complètement écrit par moi pour charger des modèles. Cela fonctionne très bien, le problème est qu'il n'utilise pas l'indexation, donc j'essaie de charger des modèles plus complexes qu'une sphère low-poly, le GPU se bloque ... Quoi qu'il en soit, j'ai essayé de le modifier pour utiliser l'indexation. même résultat .. que j'ai ajouté des index codés en dur pour les tests et j'ai eu un résultat vraiment bizarre. Quand j'avais 3 indices, il a attiré un triangle, quand j'ai ajouté 3 plus, il a tiré le même triangle et après 3 autres sommets, il a tiré 2 triangles ...

Edit: Voici ma structure Vertex:

struct Vertex:Equatable{ 
    var x,y,z: Float 
    var r,g,b,a: Float 
    var s,t: Float 
    var nX,nY,nZ:Float 

    func floatBuffer()->[Float]{ 
     return [x,y,z,r,g,b,a,s,t,nX,nY,nZ] 
    } 
} 

Répondre

3

Je vois un couple de problèmes potentiels ici.

1) Votre descripteur de sommet ne correspond pas exactement à votre structure Vertex. Les variables de position (x, y, z) occupent 12 octets, de sorte que les variables de couleur commencent à un décalage de 12 octets. Cela correspond au champ packed_float3 position dans la structure VertexIn de votre shader, mais dans le descripteur de vertex que vous fournissez à Model I/O, vous utilisez sizeof(Float3), soit 16, comme décalage de l'attribut de couleur. Parce que vous empaquetez le champ de position, vous devez utiliser sizeof(Float) * 3 pour cette valeur à la place, et de même dans les décalages suivants. Je soupçonne que c'est la principale cause de vos problèmes.

Plus généralement, c'est une bonne idée d'utiliser strideof plutôt que sizeof pour tenir compte de l'alignement, bien que - par hasard - cela ne ferait aucune différence ici.

2) Modèle E/S est autorisé à utiliser un seul MTLBuffer pour stocker les sommets et indices, vous devez donc utiliser le offset membre de chaque MTKMeshBuffer lors du réglage du tampon de sommet ou de spécifier le tampon d'index dans chaque appel de tirage au sort, plutôt que de supposer que les offsets soient 0.

+0

Salut merci :) Votre premier point a résolu le problème. La seconde n'a rien fait (Au moins je ne peux pas voir.) Mais je suppose que vous le savez mieux alors je le laisse là :) Une question de plus. Je vois que les textures semblent étranges. Je pense que c'est parce que j'utilise seulement un texel par sommet et rejette l'autre (s'il y en a plus). Pouvez-vous me donner des suggestions pour résoudre ce problème? Thx – kemkriszt

+0

Mise à jour: J'ai trouvé que je peux demander l'attribut 'MDLVertexAttributeTextureCoordinate' de' MDLMesh'. Que je pourrais le passer au shader à utiliser. Mais j'ai des problèmes. 1) Comment puis-je le convertir en tampon? Je sais comment convertir des tableaux de type c en tableaux rapides et que 'MTLBuffers' mais je ne trouve pas la longueur de l'attribut. 2) Comment puis-je savoir de quel «texel» ai-je besoin dans le shader? – kemkriszt

+0

Excellentes questions, mais ils sont hors de portée pour moi de répondre dans les commentaires - pouvez-vous poster une autre question concernant la texturation? – warrenm