2016-04-24 16 views
2

最近私はAppleのMetal APIでいくつかの実験を行っていますが、今では件名の質問になりました。1つのMetal APIシーンで異なるフラグメントシェーダーを使用する方法は?出来ますか?1つのMetal APIシーンで異なるフラグメントシェーダーを使用するにはどうすればいいですか?

背景:全体の幾何プリミティブは、色が内部で定義/計算された単純な頂点 - フラグメントチェーンによってレンダリングされます(キューブがあり、すべての面が記述された方法でレンダリングされます)。次に、プリミティブの一部を追加でテクスチャでレンダリングする必要があります(一部のピクチャを1つの面に追加する)。

これを達成するために異なるフラグメントシェーダーを使用する必要がありますか?私は最初のステップでいくつかのデフォルトのテクスチャを使用することが可能であると思うし、それはいくつかの解決策を与えるでしょう。

お勧めですか?

// =============編集部分は私が MTLRenderPipelineState の2つの異なるオブジェクトを使用しようとした更なる========== //

行きますウォーレンが示唆したように、2つの異なるレンダリング機能のペアを使用しています。次のコードがあるので、私は望みの結果を得られません。 州のそれぞれは、別々に行われたときにレンダリングされますが、一緒に実行すると、最初にがレンダリングされます。

作成レンダリング

id <MTLFunction> fragmentProgram = [_defaultLibrary newFunctionWithName:@"color_fragment"]; 

// Load the vertex program into the library 
id <MTLFunction> vertexProgram = [_defaultLibrary newFunctionWithName:@"lighting_vertex"]; 

// Create a vertex descriptor from the MTKMesh 
MTLVertexDescriptor *vertexDescriptor = MTKMetalVertexDescriptorFromModelIO(_boxMesh.vertexDescriptor); 
vertexDescriptor.layouts[0].stepRate = 1; 
vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex; 

// Create a reusable pipeline state 
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; 
pipelineStateDescriptor.label = @"MyPipeline"; 
pipelineStateDescriptor.sampleCount = _view.sampleCount; 
pipelineStateDescriptor.vertexFunction = vertexProgram; 
pipelineStateDescriptor.fragmentFunction = fragmentProgram; 
pipelineStateDescriptor.vertexDescriptor = vertexDescriptor; 
pipelineStateDescriptor.colorAttachments[0].pixelFormat = _view.colorPixelFormat; 
pipelineStateDescriptor.depthAttachmentPixelFormat = _view.depthStencilPixelFormat; 
pipelineStateDescriptor.stencilAttachmentPixelFormat = _view.depthStencilPixelFormat; 

NSError *error = NULL; 
_pipelineStateColor = [_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error]; 
if (!_pipelineStateColor) { 
    NSLog(@"Failed to created pipeline state, error %@", error); 
} 

pipelineStateDescriptor.fragmentFunction = [_defaultLibrary newFunctionWithName:@"lighting_fragment"]; 
_pipelineStateTexture = [_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error]; 
if (!_pipelineStateTexture) { 
    NSLog(@"Failed to created pipeline state, error %@", error); 
} 

- (void)renderInto:(id <MTLRenderCommandEncoder>)renderEncoder 
WithPipelineState:(id<MTLRenderPipelineState>)pipelineState 
{ 
    [renderEncoder setRenderPipelineState:pipelineState]; 
    [renderEncoder setVertexBuffer:_boxMesh.vertexBuffers[0].buffer offset:_boxMesh.vertexBuffers[0].offset atIndex:0 ]; 
    [renderEncoder setVertexBuffer:_dynamicConstantBuffer offset:(sizeof(uniforms_t) * _constantDataBufferIndex) atIndex:1 ]; 
    [renderEncoder setVertexBuffer:_textureBuffer offset:0 atIndex:2]; 
    [renderEncoder setFragmentTexture:_textureData atIndex:0]; 

    MTKSubmesh* submesh = _boxMesh.submeshes[0]; 

    [renderEncoder drawIndexedPrimitives:submesh.primitiveType 
           indexCount:submesh.indexCount 
           indexType:submesh.indexType 
          indexBuffer:submesh.indexBuffer.buffer 
         indexBufferOffset:submesh.indexBuffer.offset]; 
} 

- (void)_render 
{ 
    dispatch_semaphore_wait(_inflight_semaphore, DISPATCH_TIME_FOREVER); 

    [self _update]; 

    id <MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer]; 

    __block dispatch_semaphore_t block_sema = _inflight_semaphore; 
    [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) { 
     dispatch_semaphore_signal(block_sema); 
    }]; 

    MTLRenderPassDescriptor* renderPassDescriptor = _view.currentRenderPassDescriptor; 

    if(renderPassDescriptor != nil) 
    { 
     id <MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; 

     renderEncoder.label = @"MyRenderEncoder"; 

     [renderEncoder setDepthStencilState:_depthState]; 

     [self renderInto:renderEncoder WithPipelineState:_pipelineStateColor]; 

     [self renderInto:renderEncoder WithPipelineState:_pipelineStateTexture]; 

     [renderEncoder endEncoding]; 

     [commandBuffer presentDrawable:_view.currentDrawable]; 
    } 

    _constantDataBufferIndex = (_constantDataBufferIndex + 1) % kMaxInflightBuffers; 

    [commandBuffer commit]; 
} 

、最終的にフラグメントシェーダ

fragment float4 color_fragment(ColorInOut in [[stage_in]]) 
{ 
    return float4(0.8f, 0.f, 0.1f, 0.5f); 
} 

fragment float4 texture_fragment(ColorInOut      in [[stage_in]], 
           texture2d<float, access::sample> texture [[texture(0)]]) 
{ 
    constexpr sampler s(coord::normalized, 
         address::clamp_to_zero, 
         filter::linear); 

    return texture.sample(s, in.texture_coordinate); 
} 

答えて

2

ます複数のレンダリングパイプライン状態を作成することで、単一のフレーム/パスで複数のフラグメントシェーダを使用できます。頂点/フラグメント関数のペアごとにパイプライン状態を作成し、レンダーコマンドエンコーダでsetRenderPipelineState:を呼び出して、描画呼び出しを発行する前に適切なパイプライン状態を設定します。カラーパススルーとテクスチャサンプリングを行うために、別々のフラグメントシェーダ関数を記述する必要があります。

+0

ウォレンさん、ありがとうございます。私はそれが複数のパイプライン状態を使用することが可能であることが明らかではなかった...私はそれを試し、答えを受け入れる:) –

+1

私はそれを試みたが、私は何かが欠けているようだ...私は私が使用する実際のコードあなたがそれを見ていただければ幸いです。ありがとうございました –

+0

私はあなたのコードをコピーして貼り付けませんでしたが、驚いたことに私は自分自身でこれを試してみたときに* exact *同じエラーを出しました:2番目のフラグメント関数の名前は 'texture_fragment'ですが、第2のパイプラインを構築するときに「照明フラグメント」と呼ばれる。これは 'nil'を返し、パイプラインのラスタライズが無効になり、何も描画されません。正しい関数名を使用する場合は、すべてが賢明でなければなりません。 – warrenm

関連する問題