2016-11-22 4 views
3

Ich zeichne 2 verschiedene Vertex Puffer in Metall, eines mit einer Textur (Ignorieren Vertex Farbdaten) und das andere ohne eine Textur (Zeichnung nur die Eckpunktfarbe Daten):Texturen und keine Texturen zur gleichen Zeit in Metall, mit Multiplizieren

let commandBuffer = self.commandQueue.makeCommandBuffer() 
let commandEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: rpd) 

//render first buffer with texture 
commandEncoder.setRenderPipelineState(self.rps) 
commandEncoder.setVertexBuffer(self.vertexBuffer1, offset: 0, at: 0) 
commandEncoder.setVertexBuffer(self.uniformBuffer, offset: 0, at: 1) 
commandEncoder.setFragmentTexture(self.texture, at: 0) 
commandEncoder.setFragmentSamplerState(self.samplerState, at: 0) 
commandEncoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: count1, instanceCount: 1) 


//render second buffer without texture 
commandEncoder.setRenderPipelineState(self.rps) 
commandEncoder.setVertexBuffer(self.vertexBuffer2, offset: 0, at: 0) 
commandEncoder.setVertexBuffer(self.uniformBuffer, offset: 0, at: 1) 
commandEncoder.setFragmentTexture(nil, at: 0) 
commandEncoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: count2, instanceCount: 1) 

commandEncoder.endEncoding() 
commandBuffer.present(drawable) 
commandBuffer.commit() 

der Shader sehen aus wie:

#include <metal_stdlib> 
using namespace metal; 

struct Vertex { 
    float4 position [[position]]; 
    float4 color; 
    float4 texCoord; 
}; 

struct Uniforms { 
    float4x4 modelMatrix; 
}; 

vertex Vertex vertex_func(constant Vertex *vertices [[buffer(0)]], 
          constant Uniforms &uniforms [[buffer(1)]], 
          uint vid [[vertex_id]]) 
{ 
    float4x4 matrix = uniforms.modelMatrix; 
    Vertex in = vertices[vid]; 
    Vertex out; 
    out.position = matrix * float4(in.position); 
    out.color = in.color; 
    out.texCoord = in.texCoord; 
    return out; 
} 

fragment float4 fragment_func(Vertex vert [[stage_in]], 
           texture2d<float> tex2D  [[ texture(0) ]], 
           sampler   sampler2D [[ sampler(0) ]]) { 

    if (vert.color[0] == 0 && vert.color[1] == 0 && vert.color[2] == 0) { 
     //texture color 
     return tex2D.sample(sampler2D, float2(vert.texCoord[0],vert.texCoord[1])); 
    } 
    else { 
     //color color 
     return vert.color; 
    } 

} 

Ist das es ein besserer Weg, dies zu tun? Irgendein Vertex, den ich die Textur verwenden möchte, die ich auf Schwarz einstelle, und der Shader prüft, um zu sehen, wenn die Farbe schwarz ist, und wenn so, dann benutze die Textur, andernfalls benutze die Farbe.

Gibt es auch eine Möglichkeit, die farbigen Polys und strukturierten Polys mit einer Multiplikationsfunktion zu mischen, wenn sie sich auf dem Bildschirm überlappen? Es scheint, als hätte MTLBlendOperation nur Optionen für add/subtract/min/max, keine Multiplikation?

+0

Ich bin neu in Metall und wurden harte Zeit, wie die Nutzung verwenden mehr als eine Textur auf ein Vertex Array diese Frage wird mir helfen, es zu tun, denke ich. – Hope

Antwort

1

Eine andere Möglichkeit, dies zu tun, wäre, zwei verschiedene Fragmentfunktionen zu haben, eine, die strukturierte Fragmente rendert, und eine andere, die sich mit farbigen Scheitelpunkten beschäftigt.

Zunächst müssen Sie zwei verschiedene MTLRenderPipelineState zur Ladezeit erstellen:

let desc = MTLRenderPipelineDescriptor()  

/* ...load all other settings in the descriptor... */ 

// Load the common vertex function. 
desc.vertexFunction = library.makeFunction(name: "vertex_func") 

// First create the one associated to the textured fragment function. 
desc.fragmentFunction = library.makeFunction(name: "fragment_func_textured") 
let texturedRPS = try! device.makeRenderPipelineState(descriptor: desc) 

// Then modify the descriptor to create the state associated with the untextured fragment function. 
desc.fragmentFunction = library.makeFunction(name: "fragment_func_untextured") 
let untexturedRPS = try! device.makeRenderPipelineState(descriptor: desc) 

Dann beim Rendern, bevor das Codieren der Zeichenbefehle von einem strukturierten Objekt Sie den strukturierten Zustand gesetzt, und vor der Auslosung Befehlen kodiert eines untexturierten Objekts wechseln Sie zum untexturierten Objekt. Beispiel:

//render first buffer with texture 
commandEncoder.setRenderPipelineState(texturedRPS) // Set the textured state 
commandEncoder.setVertexBuffer(self.vertexBuffer1, offset: 0, at: 0) 
commandEncoder.setVertexBuffer(self.uniformBuffer, offset: 0, at: 1) 
commandEncoder.setFragmentTexture(self.texture, at: 0) 
commandEncoder.setFragmentSamplerState(self.samplerState, at: 0) 
commandEncoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: count1, instanceCount: 1) 

//render second buffer without texture 
commandEncoder.setRenderPipelineState(untexturedRPS) // Set the untextured state 
commandEncoder.setVertexBuffer(self.vertexBuffer2, offset: 0, at: 0) 
commandEncoder.setVertexBuffer(self.uniformBuffer, offset: 0, at: 1) 
// No need to set the fragment texture as we don't need it in the fragment function. 
// commandEncoder.setFragmentTexture(nil, at: 0) 
commandEncoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: count2, instanceCount: 1) 

Für die Scheitelpunktfunktion ist keine Änderung erforderlich. Während Sie die Fragment-Funktion in zwei Teile spalten müssen:

fragment float4 fragment_func_textured(Vertex vert [[stage_in]], 
             texture2d<float> tex2D  [[ texture(0) ]], 
             sampler   sampler2D [[ sampler(0) ]]) { 
    //texture color 
    return tex2D.sample(sampler2D, float2(vert.texCoord[0],vert.texCoord[1])); 
} 

fragment float4 fragment_func_untextured(Vertex vert [[stage_in]]) { 
    //color color 
    return vert.color; 
} 

Sie könnte sogar vorangehen und zwei verschiedene Vertex-Funktionen haben, dass die Ausgabe zwei verschiedene Vertex Strukturen, um ein paar Bytes zu speichern. Tatsächlich benötigt die Strukturfragmentfunktion nur das texCoord Feld und nicht die color, während die untexturierte Funktion umgekehrt ist.

EDIT: Sie können diese Fragment-Funktion verwenden, um sowohl die Textur und Farbe die Vertex Farbe zu verwenden:

fragment float4 fragment_func_blended(Vertex vert [[stage_in]], 
             texture2d<float> tex2D  [[ texture(0) ]], 
             sampler   sampler2D [[ sampler(0) ]]) { 
    // texture color 
    float4 texture_sample = tex2D.sample(sampler2D, float2(vert.texCoord[0],vert.texCoord[1])); 
    // vertex color 
    float4 vertex_sample = vert.color; 
    // Blend the two together 
    float4 blended = texture_sample * vertex_sample; 

    // Or use another blending operation. 
    // float4 blended = mix(texture_sample, vertex_sample, mix_factor); 
    // Where mix_factor is in the range 0.0 to 1.0. 
    return blended; 

} 
+0

Das ist so viel besser, danke :) Gibt es einen Weg den Multiplikationseffekt zu bekommen? Wenn ich es irgendwie innerhalb des Shaders machen könnte, wäre es einfach - multipliziere einfach die Tex-Farbe und die Farb-Farbe – jonydep

+0

Natürlich kannst du! Dann benutze einfach eine andere Fragmentfunktion wie diese: – ThreeDeeZero

+0

Ich werde nur die vorherige Antwort bearbeiten, um die neue Fragmentfunktion anzuzeigen. – ThreeDeeZero