2015-12-03 4 views
2

На некоторых устройствах iOS (iPhone 6s Plus) происходит частичное и произвольное исчезновение частей объекта. Как этого избежать?Странные ошибки/артефакты при рендеринге SCNNode

enter image description here enter image description here

Все палочки должны быть одинаковыми и являются клонами одной SCNNode. 16 комплекс SCNNodes, от 3 SCNNode: коробка, мяч и палка. Узел, содержащий геометрию node.flattenedClone().

Должно быть так:

enter image description here

Сode фрагмент:

func initBox() 
{ 
var min: SCNVector3 = SCNVector3() 
var max: SCNVector3 = SCNVector3() 

let geom1 = SCNBox(width: boxW, height: boxH, length: boxL, chamferRadius: boxR) 

geom1.firstMaterial?.reflective.contents = UIImage(data: BoxData) 
geom1.firstMaterial?.reflective.intensity = 1.2 
geom1.firstMaterial?.fresnelExponent = 0.25 
geom1.firstMaterial?.locksAmbientWithDiffuse = true 
geom1.firstMaterial?.diffuse.wrapS = SCNWrapMode.Repeat 

let geom2 = SCNSphere(radius: 0.5 * boxH) 

geom2.firstMaterial?.reflective.contents = UIImage(data: BalData) 
geom2.firstMaterial?.reflective.intensity = 1.2 
geom2.firstMaterial?.fresnelExponent = 0.25 
geom2.firstMaterial?.locksAmbientWithDiffuse = true 
geom2.firstMaterial?.diffuse.wrapS = SCNWrapMode.Repeat 

let geom3 = SCNCapsule(capRadius: stickR, height: stickH) 

geom3.firstMaterial?.reflective.contents = UIImage(data: StickData) 
geom3.firstMaterial?.reflective.intensity = 1.2 
geom3.firstMaterial?.fresnelExponent = 0.25 
geom3.firstMaterial?.locksAmbientWithDiffuse = true 
geom3.firstMaterial?.diffuse.wrapS = SCNWrapMode.Repeat 

let box = SCNNode() 
box.castsShadow = false 
box.position = SCNVector3Zero 
box.geometry = geom1 
Material.setFirstMaterial(box, materialName: Materials[boxMatId]) 

let bal = SCNNode() 
bal.castsShadow = false 
bal.position = SCNVector3(0, 0.15 * boxH, 0) 
bal.geometry = geom2 
Material.setFirstMaterial(bal, materialName: Materials[balMatId]) 

let stick = SCNNode() 
stick.castsShadow = false 
stick.position = SCNVector3Zero 
stick.geometry = geom3 
stick.getBoundingBoxMin(&min, max: &max) 
stick.pivot = SCNMatrix4MakeTranslation(0, min.y, 0) 
Material.setFirstMaterial(stick, materialName: Materials[stickMatId]) 

box.addChildNode(bal) 
box.addChildNode(stick) 

boxmain = box.flattenedClone() 
boxmain.name = "box" 
} 

Добавить узлы сцены:

func Boxesset() 
{ 
    let Boxes = SCNNode() 
    Boxes.name = "Boxes" 

    var z: Float = -4.5 * radius 
    for _ in 0..<4 
    { 
     var x: Float = -4.5 * radius 
     for _ in 0..<4 
     { 
      let B: SCNNode = boxmain.clone() 
      B.position = SCNVector3(x: x, y: radius, z: z) 
      Boxes.addChildNode(B) 
      x += 3 * Float(radius) 
     } 
     z += 3 * Float(radius) 
    } 
    self.rootNode.addChildNode(Boxes) 
} 

Это проверено и отлично работает на симулятор - все устройства, на физических устройствах - iPad Retina и iPhone 5.

Глюч наблюдается только на ультрасовременном iPhone 6s Plus (128 Gb).

The problem is clearly visible on the video ->

enter image description here

Проблема с графикой может быть решена путем изменения по умолчанию рендеринга API для OpenGL ES ...

... но вы можете имеют неожиданные проблемы в чистых вычислительных модулях, которые не связаны с графикой на iPhone 6S Plus. (у iPhone 6 таких проблем нет).

Что случилось?

+0

На симуляторе iPhone 6s Plus все выглядит нормально. –

+2

Можете ли вы уточнить, что не так, и что показывают скриншоты? – mnuages

+1

@ EricD. Спасибо за помощь. –

ответ

1

Просто скажите, я не знаю правильного ответа на мой вопрос, но я нашел приемлемое решение для себя.

Оказалось, все это в «рассеянном» свойстве SCNMaterial.

По какой-то причине металл не очень нравится при диффузии = UIColor (...) Но если хотя бы один элемент в составном SCNNode (как в моем случае) является diffuse.contents = UIImage (...) , тогда все начинает работать отлично.

работает

diffuse=<SCNMaterialProperty: 0x7a6d50a0 | contents=<UIImage: 0x7a6d5b40> size {128, 128} orientation 0 scale 1.000000> 

не работает

diffuse=<SCNMaterialProperty: 0x7e611a50 | contents=UIDeviceRGBColorSpace 0.25 0.25 0.25 0.99> 

Я нашел решение этой проблемы просто:

Я просто добавил один маленький, незаметный элемент с диффузным .contents = UIImage (...) к существующим 3 элементам с diffuse.contents = UIColor (...), и он отлично работает.

Итак, мои рекомендации:

  • быть осторожным при работе с металлом. (У меня есть проблемы на устройствах 5S и выше)

  • тщательно проверить SceneKit приложения на реальных устройствах, не доверяют только Тренажер

Я надеюсь, что это временные ошибки, и это будет исправить в будущих выпусках Xcode.

Приятные приложения!

P.S. Кстати, готовое приложение полностью бесплатное в AppStore сейчас Qubic: tic-tac-toe 4x4x4

2

TL; DR

Добавить scnView.prepareObject(boxmain, shouldAbortBlock: nil) в конце вашего initBox.

Я быстро просмотрел ваш код, работающий на моем 6s Plus, и увидел похожие результаты. Один из угловых узлов отсутствовал и постоянно пропускал каждый прогон. Но у нас не работает тот же код, у меня отсутствуют данные о материалах ...

SceneKit ленив, часто вещи не выполняются до тех пор, пока объект не будет добавлен в сцену. Я впервые наткнулся на эту извлечение геометрии из примитива SceneKit (SCNSphere и т. Д.), Вы обнаружите это, когда клонируете что-то с помощью следующих строк.

let B: SCNNode = boxmain.clone() 
... 
boxmain = box.flattenedClone() 

Я бы сказал, что SceneKit просто не завершает клон перед тем, как второй клон встречается последовательно. Я точно не знаю этого.

Удаление первого клона устраняет эту проблему для меня. Например, замените boxmain = box.flattenedClone() на boxmain = box.Но я бы сказал, что вы сделали, это лучшая практика, сглаживание этих узлов приведет к сокращению числа обратных вызовов и повышению производительности (возможно, это не проблема на 6s).

SceneKit также предоставляет способ - prepareObject:shouldAbortBlock:, который будет выполнять операции, необходимые перед добавлением объекта в сцену (в этом случае .flattenedClone()).

Добавление следующей строки в конец вашей функции initBox также устраняет проблему и является лучшим решением.

scnView.prepareObject(boxmain, shouldAbortBlock: nil) 
+0

Большое спасибо за подробный ответ. Я смотрел на prepareObject, но на самом деле не понимал (и не понимаю сейчас), почему это необходимо в этой ситуации. Почему некоторые объекты отображаются нормально, а другие - нет, хотя все они находятся на равных условиях? И это происходит только на новых iPhone. Это больше похоже на недостаточную мощность на графической карте, но думать так плохо о новом ребенке Apple - это грех))). –

+0

Такая сложная конструкция объектов, в которых мне нужно жестко распознавать распознаватель, уникально определенную постукиваемую палку, независимо от того, какую часть палки я постучал. В предлагаемой реализации он отлично работает. Я буду следовать вашим советам и написать отчет о результатах. –

+0

Согласен. Все, что я когда-либо делал в Scene Kit, показало, что это ленивая загрузка всего и вся. – Confused

Смежные вопросы