在 draw() 循环中重新使用 currentDrawable.texture 时的 MTKView 混合问题

Posted

技术标签:

【中文标题】在 draw() 循环中重新使用 currentDrawable.texture 时的 MTKView 混合问题【英文标题】:MTKView blend issues when re-using currentDrawable.texture in draw() loop 【发布时间】:2019-08-11 19:49:04 【问题描述】:

我正在开发一个金属支持的绘画应用程序,在该应用程序中,我将笔画的绘制分为两个步骤:第一步将笔画的前缘绘制到屏幕上,然后通过以下方式将整个内容捕获到 MTLTexture:

metalTextureComposite = self.currentDrawable!.texture

第二步绘制前进笔划的更新前边缘,并在使用最后保存的 metalTextureComposite 纹理的多边形顶部进行合成。

这种方法允许我在不牺牲性能的情况下绘制无限长的笔划,因为这两个步骤在绘制周期的每一帧中都会重复。

我遇到的问题是,使用所需的复合源模式(见下面的代码),我只看到笔划的前沿被绘制到屏幕上。这告诉我要么我没有从 currentDrawable 中充分捕获 metalTextureComposite,要么我对要使用的混合模式做出了错误的假设,顺便说一下如下:

renderPipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = .sourceAlpha
renderPipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha       
renderPipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .sourceAlpha                 
renderPipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha

如果我使用不同的混合模式,我确实会看到正在绘制的整个笔触,但不一定是我想要的外观。下面是我包含在 MTKView 的 draw() 方法中的部分代码。

func metalRenderStampArray() 

    // first encode uber-stamp with previous loop's  metalTextureComposite in a background polygon
    // note metalTexture= metalTextureComposite contains previous loop's drawable contents
    metalCommandEncode(renderCommandEncoder: renderCommandEncoder, stampLayer: stampLayerMode.stampLayerBG, vertexArrayStamps: vertexArrayStampsBG, metalTexture: metalTextureComposite) // background uber-stamp

    // empty out uber-stamp in preparation for the next cycle
    initializeStampArrays(stampLayer: stampLayerMode.stampLayerBG) 

    // next, encode current subCurve chunk polygons in foreground
    // note metalTexture=brushTexture.texture is a round brush texture with alpha
    metalCommandEncode(renderCommandEncoder: renderCommandEncoder, stampLayer: stampLayerMode.stampLayerFG, vertexArrayStamps: vertexArrayStampsFG, metalTexture: brushTexture.texture) // foreground sub-curve chunk

    renderCommandEncoder?.endEncoding() // finalize renderEncoder set up

    // now present bg + fg composite which is where I see the problem
    commandBuffer?.present(self.currentDrawable!)

    // 7b. Render to pipeline
    commandBuffer?.commit() // commit and send task to gpu

    metalTextureComposite = nil // empty out before re-populating
    metalTextureComposite = self.currentDrawable!.texture // set up bg texture for next iteration 

    metalStampComputeComposite() // compute coordinates for the background composite stamp for the next iteration

  // end of func metalRenderStampArray()

我是否应该以不同的方式处理 metalTextureComposite(因为它是以 1/fps 的速度写入的),如果是这样,我应该如何处理它?目标是为背景多边形和前导笔划多边形使用单一混合模式。任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

您似乎正在存储对可绘制对象纹理的引用,然后在下一帧使用它。

我可以看到 2 个可能的问题: - 在下一帧绘制周期,前一帧的纹理可能还没有被图形处理器绘制到 - 系统和应用程序代码可能同时使用drawable的纹理

我建议尝试在commandBuffer?.addCompletedHandler 中复制drawable 的纹理供您使用

【讨论】:

以上是关于在 draw() 循环中重新使用 currentDrawable.texture 时的 MTKView 混合问题的主要内容,如果未能解决你的问题,请参考以下文章

UIView重新渲染布局时,不会触发draw函数

al_draw_filled_rectangle() 似乎只在某些类中有效

带有 GL_DYNAMIC_DRAW 的 OpenGL VAO

通过JAVA在mongodb中获取currentdate

编写游戏循环的困惑

将 svg 从 Inkscape 导出到 Corel Draw