Как заставить motion blur работать в SceneKit?

#objective-c #swift #scenekit

#objective-c #swift #scenekit

Вопрос:

Согласно WWDC 2017, motionBlurIntensity была добавлена в качестве свойства в SCNCamera. Я пробовал следующее, но не смог заставить SceneKit размыть мою сцену при перемещении камеры:

  • Установите wantsHDR в true
  • Добавьте SCNDisableWideGamut в виде логического значения со значением YES в каждый Info.plist в моем проекте Xcode
  • Переместите SCNBox, изменив положение его SCNNode перед камерой, установив для motionBlurIntensity значение 1.0
  • Переместите саму камеру, изменив положение ее SCNNode, установив для motionBlurIntensity значение 1.0
  • Анимируйте камеру, используя SCNTransaction с motionBlurIntensity, установленной на 1.0, вместо того, чтобы менять ее положение каждый кадр
  • Проделайте вышеуказанное, установив интенсивность motionBlurIntensity равной 500 или выше

Я запускаю следующий код для каждого отображаемого кадра следующим образом:

     camNode.position = SCNVector3Make(cx, cy, cz);
    camNode.eulerAngles = SCNVector3Make(rotx, roty, rotz);
    camNode.camera.wantsDepthOfField = enableDOF;
    camNode.camera.wantsHDR = enableHDR;

    camNode.camera.zNear = camNearVal;
    camNode.camera.zFar = camFarVal;
    camNode.camera.focalLength = camFocalLength;

    camNode.camera.usesOrthographicProjection = usingOrthoProjection;
    if(!usingOrthoProjection)
    {
        camNode.camera.projectionTransform = SCNMatrix4FromGLKMatrix4(GLKMatrix4MakeWithArray(projection));
    }
    else
    {
        // Ortho options
        camNode.camera.orthographicScale = orthoScale;
        if(cam_projectionDir == 1)
            camNode.camera.projectionDirection = SCNCameraProjectionDirectionHorizontal;
        else
            camNode.camera.projectionDirection = SCNCameraProjectionDirectionVertical;
    }

    // DOF
    camNode.camera.sensorHeight = dof_sensorHeight;
    camNode.camera.focusDistance = dof_focusDistance;
    camNode.camera.fStop = dof_fStop;
    camNode.camera.apertureBladeCount = dof_apertureBladeCount;
    camNode.camera.focalBlurSampleCount = dof_focalBlurSampleCount;

    // Motion blur
    camNode.camera.motionBlurIntensity = motionBlurIntensity;
  

И здесь SCNRenderer устанавливает свой pointOfView для камеры:

     mainRenderer.scene = mainScene;
    mainRenderer.pointOfView = camNode;
    id<MTLCommandBuffer> myCommandBuffer = [_commandQueue commandBuffer];

    [mainRenderer updateAtTime: currentFrame];
    [mainRenderer renderWithViewport:CGRectMake(0,0,(CGFloat)_viewWidth, (CGFloat)_viewHeight) commandBuffer:myCommandBuffer passDescriptor:_renderPassDescriptor];

    [myCommandBuffer commit];
  

Эффекты HDR, такие как Bloom и SSAO, работают должным образом, но не размытие при движении.
Я использую Xcode версии 10.1 на macOS Mojave.
Я запустил пример приложения Badger, и motion blur в этом проекте работает на моем компьютере.
Я что-то здесь упускаю? Любая информация была бы высоко оценена.

Комментарии:

1. Попробуйте один раз установить интенсивность размытия движения камеры на 1.0, а не на каждом кадре.

2. Спасибо за ответ. Проверял, не повезло. Тем не менее, я думаю, у меня есть представление о том, что здесь не так. Я пытаюсь визуализировать по одному кадру за раз. Возможно, данные предыдущего кадра недоступны SceneKit, если они не выполняются непрерывно? Я знаю, что в примере Badger для рендеринга материала используется SCNView.

Ответ №1:

Значение motionBlurIntensity свойства по умолчанию равно 0.0 . Это не приводит к эффекту motion blur. Более высокие значения (максимально приближающиеся к 1.0) создают более выраженные эффекты motion blur. Размытие при движении не поддерживается, когда включена цветопередача с широким диапазоном. Рендеринг с широким охватом включен по умолчанию на поддерживаемых устройствах; чтобы отказаться, установите ключ SCNDisableWideGamut в файле Info.plist вашего приложения.

Протестируйте это с помощью моего кода:

 let cameraNode1 = SCNNode()
cameraNode1.camera = SCNCamera()
cameraNode1.camera?.motionBlurIntensity = 3          // MOTION BLUR
scene.rootNode.addChildNode(cameraNode1)

let move = CABasicAnimation(keyPath: "translation")
move.fromValue = NSValue(scnVector3: SCNVector3(x: 7, y: -5, z: 0))
move.toValue = NSValue(scnVector3: SCNVector3(x: 7, y: 5, z: 0))
move.duration = 0.5
move.repeatCount = 20
move.autoreverses = true
move.repeatCount = .infinity

let sphereNode1 = SCNNode()
sphereNode1.geometry = SCNSphere(radius: 2)
sphereNode1.addAnimation(move, forKey: "back and forth")
scene.rootNode.addChildNode(sphereNode1)
  

Работает отлично.