为什么Xcode 8.1 + Metal。崩溃我用来操作我的3D模型的计时器?

时间:2016-10-31 23:00:48

标签: nstimer metal

我有一个弧形机械手,它使用Timer来创建当前旋转角度的平滑减速衰减。它在我的GL应用中运行得很好。在Metal中,它会崩溃该应用。

以下是我实例化计时器的方法:

rotationTimer = Timer.scheduledTimer(
timeInterval: TimeInterval(kRotationRate), 
target: self,
selector: Selector(("rotationTimerHandler")),
userInfo: [ "radiansBegin":radians, "radians":radians, "radiansEnd":0, "counter":0 ],
repeats: true)

函数rotationTimerHandler递减角度 - radians - 然后从中构建一个转换矩阵,它包含在渲染绘制循环的更新函数中。

我怀疑我需要与Metal绘制循环的时序进行一些同步,但我认为没办法这样做。如何让TimerMetal一起玩得很好?

更新0

Per Warren的问题风暴:-)这里有更多的背景。

我的应用视图是MTKView,有2个属性。

符合MTKViewDelegate协议并实现的渲染器:

func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize)
func draw(in view: MTKView)

绘图由MTKView的内部显示链接计时器驱动。一切都在主线程上运行。没有异步调用。

和一个弧形球。将屏幕手势映射到四元数到3D旋转矩阵的对象。 arcball是视图的平移手势处理程序:

addGestureRecognizer(UIPanGestureRecognizer.init(
    target: arcBall,
    action: #selector(EIArcball.arcBallPanHandler)))

}

当弧形球的平移手势处理程序进入结束状态时,我实例化一个计时器N秒,以便在平移结束时基于角度/旋转轴继续生成四元数/矩阵,以获得令人愉悦的滑动效果。

好的,渲染器(符合MTKViewDelegate)。绘制循环:

public func draw(in view: MTKView) {

    update(view: view as! EIView, drawableSize: view.bounds.size)

    // final pass
    if let passDescriptor = view.currentRenderPassDescriptor, let drawable = view.currentDrawable {

        passDescriptor.colorAttachments[ 0 ].clearColor = MTLClearColorMake(0.5, 0.5, 0.5, 1.0)

        let commandBuffer = commandQueue.makeCommandBuffer()

        let renderCommandEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: passDescriptor)

        renderCommandEncoder.setFrontFacing(.counterClockwise)
        renderCommandEncoder.setTriangleFillMode(.fill)
        renderCommandEncoder.setCullMode(.none)

        renderCommandEncoder.setRenderPipelineState(heroModelPipelineState)
        renderCommandEncoder.setVertexBuffer(heroModel.vertexMetalBuffer, offset: 0, at: 0)
        renderCommandEncoder.setVertexBuffer(heroModel.metallicTransform.metalBuffer, offset: 0, at: 1)
        renderCommandEncoder.setFragmentTexture(heroModelTexture, at: 0)
        renderCommandEncoder.drawIndexedPrimitives(
                type: .triangle,
                indexCount: heroModel.vertexIndexMetalBuffer.length / MemoryLayout<UInt16>.size,
                indexType: MTLIndexType.uint16,
                indexBuffer: heroModel.vertexIndexMetalBuffer,
                indexBufferOffset: 0)

        renderCommandEncoder.endEncoding()

        commandBuffer.present(drawable)
        commandBuffer.commit()
    }

}

这里没什么特别有趣的。请注意电话:

update(view: view as! EIView, drawableSize: view.bounds.size)

以下是update

func update(view: EIView, drawableSize:CGSize) {

    heroModel.metallicTransform.update(camera: camera, transformer: {
        return view.arcBall.rotationMatrix * GLKMatrix4MakeScale(150, 150, 1)
    })

}

function heroModel.metallicTransform.update(...)构建我的顶点着色器中使用的模型 - 视图 - 投影矩阵。这是一个玩具应用程序,它将x-y缩放的四边形绘制为150,通过平移手势操纵(旋转)到弧形球。

update中,我没有尝试安排使用arcball的变换矩阵进行更新。这似乎是代码味道。

这是crasher screendump: enter image description here

我越想到这一点似乎我应该明确地进行绘制调用,因为我没有必要不断地重绘。 1)平移时只需调用renderer.draw()。 2)平移结束后,从我的Timer处理程序中调用render.draw()。

更新1

这是更多的堆栈跟踪。只是一大堆汇编程序:

enter image description here

更新2

bt(backtrace)的输出:

enter image description here

我想我会尝试在没有内部计时器的情况下运行Metal 并明确调用MTKView.draw()。在这样一个简单的应用程序中不需要基于计时器的方法,并且基于NSTimer的Arcball也存在问题。

1 个答案:

答案 0 :(得分:0)

解决。我决定保留使用card_names内部计时器,并在NSTimer回调中平移期间在 public function sortupdate(Request $response) { $get_result_arr = json_decode($response->getContent()); foreach($get_result_arr as $result){ $lists = $result->lists; } } 中明确调用MTKView。十分简单。工作方式相同。

代码:https://github.com/turner/HelloMetal