SceneKit的厄运
SceneKit — 3Dграфики,которыйпоможетвомсоздаватьанимиреенныененные3D Онвключаетвсебяфизическийдвижок,генераторчастицинаборпростыхдействийдля3Dобъектов,которыепозволятвамописатьвашусценувтерминах контента – геометрии,материалов,освещения,камер – ианимироватьеёчерезописаниеизмененийдляэтих объектов 。
– 苹果
Сегоднямывнимательным,немногосуровымвзглядомпосмотримнаSceneKit,но,дляначала,обратимсякосновам,ипосмотрим,чтопредставляетизсебя3Dсцена,ичтонужносделать,чтобыеёсоздать。
Дляначала,нужносоздатьосновнуюструктурусцены,котораясостоитизнод,илиузловсцены。 Каждаянодаможетсодержатьвсебекакгеометрию,такидругиеноды。 Геометрияможетбытьпростой,вродешара,куба,илипирамиды,такиболеесложной,созданнойво。
Затем,дляэтойгеометриинеобходимозадатьматериалы,которыебудутопределятьбазовоепредставла。 Каждыйматериалсамзадаётсвоюмодельосвещения,и,взависимостиотнеё,используотвазличный。 Каждоетакоесвойствообычнопредставляетизсебяцветилитекстуру,но,помимоэтихчастоиспользуемыхвариантов,естьещёвозможностьиспользовать的CALayer,AVPlayer,иSKScene。
Послеэтого,необходимодобавитьисточникиосвещения,которыеопределяютто,насколькоооо Они,поаналогиисгеометрией,должнылежатьвнутрикакой-нибудьноды。 SceneKit是Поддерживаетмногоразныхтиповосвещения或такженескольковидовтеней的产品。
Затемнужносоздатькамеру(иположитьеёвотдельнуюноду)изадатьдлянеёосновныепараметры。 Ихдовольномного,но,спомощьюнихможносоздаватькрутыеэффекты。 Изкоробкиподдержибокэ(илиэффектразмытия),HDRсадаптацией,свечение,SSAOиоооии。
И,наконец,SceneKit在3Dобъектов,которыепозволяюннетевель Такжесценкитподдерживаетдействия,JavaScript,ноэтотемадляотдельнойстатьи。
Помимографики,главнымифишкамиSceneKit’аявляютсягенераторчастиципродвинутыйфизическийдвижок,которыйпозволяетзадаватьреальныефизическиесвойствакакобычнымобъектам,такисчастицамизгенератора。
Провсеэтифишкинаписанобольшоеколичествотуториалов,которыерассказываютпронихвововоо。 Новпроцессеразработкимыэтивозможностипрактическинеиспользовали…
Однажды,янаписалмодельосвещениядля3D-игрлучшереальногосолнечногосвета,дающуюприемлемуюFPSнаNvidia的8800,ноярешилневыпускатьдвижоквсвет,таккакБогмнесимпатичен,иянехочупоказыватьегонекомпетентностьв этомвопросе 。
—ДжонКармак
Подробноеизучениемыначнемсдовольнопростойзадачи,котораявозникаетпрактическиувсех,работающихсоSceneKit’омдовольносерьёзно:какзагрузитьмодельсосложнойгеометриейиподключеннымиматериалами,освещением,даещеисанимациями?
Естьнесколькоспособов,ивсеониимеютсвоиплюсыиминусы:
- SCNScene(named)—получаетсценуизбандла;
- SCNScene(url:options 🙂 —загружаетсценупоurl;
- SCNScene(mdlAsset 🙂 —конвертируетсценуизразныхформатов;
- SCNReferenceNode(URL 🙂 —ленивозагружаетсцену。
Получаемсценуизбандла
Можновоспользоватьсяметодом:положитьнашумодель。
Ночтоделать,есливыхотитесамиконтролироватьобновлениемоделей,невыпускаяобнове Иливыхотитеподдержатьсозданныепользователямикартыимодели? Илидажевепростонехотитеувеличиватьразмерприложения,таккак3Dграфиканеявоеосевашей
Загружаемсценупоurl
МожноиспользоватьконструкторсценыизURL .scnфайла。 Этотспособподдерживаетзагрузкунетолькоизфайловойсистемы,ноиизсети,но,воониеном。 Плюс,впотребуетсязаранеесконвертироватьмодельвформатscn。 Можно,конечно,использоватьиdae,носнимприходитнаборограничений,например,отсутствие基于物理渲染。
Главныйплюсэтогоспособа— —онпозволяетгибконастраиватьпараметрыимпорта。 Можно,например,модифицироватьжизненныйцикланимаций,изаставитьихбесконечноповторяться。 Можноявноуказатьместо,откудазагружатьвнешниересурсы,вродетекстур,можноконвертироватьориентациюимасштабсцены,создаватьотсутствующиенормалидлягеометрии,смержитьвсюгеометриюсценыводнубольшуюноду,илиотброситьвсенесоответствующиестандартуформатаэлементысцены。
Конвертируемсценуизразныхформатов
Третийвариант—和MDLAsset关联。 Тоесть,сначаламысоздаемMDLAsset,доступныйвфреймворкеModelIO,изатемпередаёмеговконструктордля。
хтотвариантхороштем,чтоумеетзагружатьмногоразличныхформатов。 ОфициальноMDLAssetумеетзагружатьOBJ,帘布层,STLиUSDформаты,но,прогнавсписоквсехвозможныхформатовхотькак-тосвязанныхскомпьютернойграфикой,янашёлеще4:ABC,BSP,VOXиMD3,ноонимогутподдерживатьсянеполностьюилине вовсехсистемах,идлянихнужнопроверятькорректностьимпорта。
Также,нужноучитывать,чтоэтотметодимеетоверхеднаконвертацию,такчтоегонужоокуниспользов。
在SCNScene中,或在SCNNode上。 Иединственныйспособдобавитьконтентвужесуществующуюсцену – скопироватьвседочерниеноды,и,чтоможнолегкопропустить,анимацииизкорневойноды(Они,например,могутпоявитьсятамприработесDAE)。 Ктомуже,нужноучитывать,чтовсценетекстураокруженияможетбытьтолькоодна(елеве
Ленивозагружаемсцену
—етвертыйвариант— SCNReferenceNode。 Онвозвращаетнесцену,аноду,котораяможетсамалениво(илипо-запросу)загружитевсебявсю。 Такимобразом,этотспособаналогиченпервому,ноонскрываетвнутрисебявсепроблемыскопирова。
Унегоестьодноно:онтеряетглобальныепараметрысцены。
Получается,этосамыйпростойибыстрыйспособзагрузитьвашумодельку,но,есливамнуженфайн-т
Витогемыостановилисьнапервомварианте,таккакнамбылоудобнеевсегоработатьвформате.scn,адизайнерам – конвертироватьвнегоизформатаDAE,инампонадобилсяфайн-тюнинганимацийпризагрузке。
Вовсенепреждевременныеоптимизации
Поработавсэтимпроцессомдостаточнодолго,ямогудатьвамнесколькосоветов:
Самыйглавныйсовет – конвертируйтефайлывSCNзаранее,тогдавысможете,открывфайлвовстроенномв的Xcodeредакторесцен,увидетькакименнобудетвыглядетьвашобъектвSceneKit’е。
。 Длятогожеdaeнужносачалараспарситьxml,потомсконвертироватьвеемеши,анимациииматериалы。
Темболее,чтоконвертацияанимацийиматериалов—потенциальныйисточникпроблем。 ВспоминаемотсутствиеподдержкиPBRвDAE:получается,есливыхотитеегоиспользовать,вамприйдётсяпослеконвертациисменитьтипвсехматериаловивручнуюпроставитьсоответствующиетекстуры。
Приэтойоперацииможнополучитьоченьполезныйсайдэффект:значительноесжатиетекстур。 Дляэтогооткройтеихв«просмотре»иэкспортируйте,сменивформатна.heic。 Всреднем,этапростаяоперациясэкономилапо5мегабайтнамодель。
Также,есливыскачиваетесценуизинтернета,могупосоветоватьзагружатьсценувае Этосэкономитвипользователюлишниемегабайты,чтоускоритзагрузку,атакженомоттель Согласитесь,накаждыйресурсделатьотдельныйзапрос,
Когдаяедунамашине,ячастослышу,какпотрескиваетжёсткийдискВселенной和подгружаяследуюуую。
—ДжонКармак
西班牙 Иужповерьте,здесьестьочемрассказать。 SceneKit’е中的Начнеммыстого,чтопройдёмсяпоразличнымконстрейнтам。
Констрейнтам,скажетевы? Какимконстрейнтам? Именнотак。 Малоктознает,атемболееирассказываетобэтом和SceneKit’еестьсвойнаборконстрейнтов。 Ихотяонинетакиегибкие,UIKit’екакконстрейнты,спомощьюнихвсёравноможноможносделатьнногои。
Начнёмспростогоконстрейнта— SCNReplicatorConstraint。 Всё,чтоонделает—этодублируетпозицию,поворотиразмердругогообъектаcдополнительнымиоф。 Какиувсехостальныхконстрейнтов,унегоможноменятьсилу,ивыставлятьфлагинкрементальности,илучшевсегоэтипараметрыможнопоказатьнаэтомконстрейнте。
Силавлияетнато,скакимкоэффициентомтрансформацияприменяетсякобъекту。 Иразположениеобъекта-целименяетсякаждыйкадр – шадоуобъектприближаетсякнемунаоднудесятуюотразницырасстояний,ииз-заэтогопоявляетсяэффектзапаздывания。
Инкрементальностьжевлияетнато,отменяетсяликонстрейнтпослерендеринга。 Еслиеговыключить-тооннакаждомкадреконестрейнтприменяетсяпередрендерингом, Врезультате,комбинируяэтидвапараметраможнополучитьдовольноинтересныйэффектстрелкичасов
Перейдёмкболееинтересномуконстрейнту:такназываемомубиллборду。
Допустим,необходимо,чтобынекоторыйобъектвсегданаходилсякнам«лицом»。 Дляэтого,нужновсеголишьиспользоватьSCNBillboardConstraint,иуказать,вокругкакихосейобъектможетповорачиваться,и,дальше,передпросчётомкаждогокадра(послешагасфизикой)позициииориентациивсехобъектовбудутобновляться,чтобыудовлетворитьвсемконстрейнтам。
Тутжеможноупомянуть看约束:онаналогиченBillboard’у,тольковместотекущейкамеры,объектможно
Чтоможносделатьсихпомощью? Чащевсего,конечноже,этиконстрейнтыприменяютсядлярисованиядеревьев,илимелкихобъектов。 Такжесихпомощьюсоедеффекты,
SCNDistanceConstraintпозволяетзадатьминимальноеи/илимаксимальноерасстояниедопозициидругогообъекта。 Ида,сегопомощьюможносделатьзмейку:)Этотконстрейнттожеможноиспользоватьдляпривязкикамерыкперсонажу,хотя,положениекамерыобычнозадаётсяболеесложно,иоднимиконстрейнтамиегосложноописать。 Тотжеэффектможнодостичьзасчётдобавленияпружинывфизическомдвижке,ноэтупружинуможнодополнитьконстрейнтомнаслучай,еслинужноизбежатьпроблемсизлишнимрастягиванием/сжатиемпружины。
Многиевидели,каквкаком-нибудьHitman’е,Fallout’еилиSkyrim’е,бываеттакое,чтотытащишьтелозасобой,ионозадеваетпрепятствие,ителовнезапноначинаетвестисебякакбудтовнеговселилсядемон。 Таквот,этотконстрейнтпомогбыизбежатьтакихбагов。
SCNSliderConstraintпозволяетзадатьминимальноерасстояниемеждузаданнымобъектомифизическимоисева Довольнозабавныйконстрейнт,но,опятьже,егостараютсясимулироватьспомощьюфизическоговзаим。 Основнаяидея—задатьрадиусмертвойзонысфизическимителамидляобъекта,которыйнеиеетфиз。
SCNIK约束。 Самыйинтересный,ноисамыйсложныйконстрейнт,которыйиспользуеттакназываемуюинверснуюкинематику,котораяитеративнопытаетсяприблизитьположениеноды,ккоторомувыприменяетеэтотконстрейнткнеобходимойточке,используяцепочкуродительскихузлов。 Посути,онпозволяетнедуматьотом,вкакомположениидолжнынаходитьсяплечоипредплечье,апростозадатьположениекистирукиивозможныеуглыповоротасвязующихузлов,аостальноепосчитаетсязавас。 Основнойнедостатокэтогоконстрейнта – онпозволяетлишьзадатьположениекистируки,нонееёориентацию,даиограничениянауглыможноделатьглобальное,безразбивкипоосям。
Итак,мыподробнопознакомилисьсконстрейнтами,ичтоониумеютделать。 Давайтепродолжимизтчининтересныеэффекты,以及разберемсясэффектомтеней。
Казалосьбы,чтоможетбытьпрощевдвижке,которыйподдерживаеттени,чемсозданиетеней? Но,иногда,тенинужноотброситьнаполностьюпрозрачнуюплоскость。 Kitтооченьполезно或ARKit’е,таккакзаплоскостьюотображаетсяизображениекамеры,атеньоотеньдолезно。 Трюкоказываетсядовольнопрост:нужносначалавключитьотложенныетенииотключитьзаписьвовсекомпонентыуплоскостивовкладкематериала,итеньпродолжитнакладыватьсянанеё。 Единственнаяпроблема—этаплоскостьбудетперекрыватьобъектынаходящиесязаней。
Нотени—неединственныйслабоизученныйэффектвсценките。 Давайтетеперьразберемсясзеркалами。
Все,ктоигралсясосценкитом,наверняказнаютоscnfloor,которыйдобавляетзеркальныеотражениядл。 Но,почему-то,оченьмалоктоиспользуетегодлячестныхзеркальныхотражений,ведьнадгеометриейполаможноположитьсвоюмодельку,немногонаклонить,ипревратитьего…вобычноезеркало。
Но,чтоещёменееизвестно – дляэтогополаможновыставитькартунормалей,и,засчётэтого,можносоздатьмногоразныхинтересныхэффектов,вродеэффектапотёков,иликривогозеркала。
Однаждыяцеловалсясдевушкойсоткрытымиглазами。 Ближнейплоскостьюотсечениядевушкерассеклолицо。 Стехпоряцелуюсьтолькосзакрытымиглазами。
—ДжонКармак
Тени,зеркала—интересныеэффекты。 Ноестьодинэффект,который,приумеломиспользовании,можетоказатьсяещёболееинтересным—виде
Онимогутвтонт,нт,чтогораддине Дляэтого,вамнужноположитьвидеотекстурускартойвысотвсвойство位移вашегоматериалаииспользоватьматериалнаплоскостисдостаточнобольшимколичествомсегментов。 Осталосьпонять,какжееётудаположить。
Яупоминалвописаниипроцессасозданиясцены,чтовкачествесвойстваматериалавыможетеиспользоватьSKScene,аэто – SpriteKit’оваясцена(SpriteKit – этокакSceneKit,нодля2Dграфики)。 使用SKVideoNode进行操作。 Всё,чтовамнужносделать—从SKVideoNode到SKScene,再到SKScene到SCNMaterialProperty,再到вссготово。
Но,экспортировавполученнуу3Dсценуиоткрывеёгде-нибудьеме,мыувидимчерныйквадрат。 Покопавшисьв.scnфайле,янашёлпричину。 Оказывается,присохранениивидеоноданесохраняетurlвидео。 Казалосьбы,берешьиправишь。 Ноневсётакпросто:.scnфайлпредставляетизсебятакназываемый二进制plist,由которомлежитрезультат密钥。 Иматериал,которыйявляетсяSpriteKit’овойсценой,представляетизсебятакой二进制plist,который,получее Хорошо,чтоуровнявложенностивсегодва。
Нуатеперьмыперейдёмдаженекэффекту,акинструменту,которыйпозволитвамсоддтткакие
Итак,передтем,какчто-томодифицировать,надопонять,чтоименномымодифицируем。 GPUейдер,поопределению,этопрограммадляGPU,котораяпрогоняетсядлякаждойвершиныилликаждог。 Такимобразомшейдер—этопрограмма,котораяопределяет,каквыглядитобъектнаэкране。
ШейдермодификаторыжепозволяютменятьрезультатыработыстандартныхшейдеровнаGLSLили金属着色语言,и,которые,ктомуже,доступныввизуальномредакторе,чтопозволяетвидетьвидетьизменениявмодификаторевреальномвремени。
Спомощьюнихможносоздаватьсложнейшиевизуальныеэффекты。 Вот,например,парочкасамыхизвестныхэффектов:мехипараллаксмэппинг。
,тоещёинтереснее,никтонемешаетполностьювыкинутьрезультатыихработы,инаписатьсвойренд。 Например,МожнопопробоватьреализоватьRay Castingвшейдерах。 Ивсёэтоработаетдостаточнобыстро,чтобыобеспечить每秒30 fps。 Ноэтотемадляотдельногодоклада。 ПриходитенаMobius!
тнелюблюморгать,т。 к。 在BDPT上使用GPU或BDPT进行图形处理。
—ДжонКармак
Итак,您在кучаобъектовскласснымиэффектами。 Теперьосталосьнаучитьсяихзаписывать。 Дляэтогоперейдёмкболеесложнойтеме:какмынаучилисьзаписыватьвидеонапрямуюизSceneKit’aбезвнешнегоUI,икакмыоптимизировалиэтузаписьвдесяткираз。
Давайтесначалаобратимсяксамомупростомурешению:ReplayKit,ивыясним,почемуононеподходит。 Вообщеговоря,эторешениепозволяетвнесколькостроккодасоздатьзаписьэкрана,иссохранитье Но。 Унегоестьбольшойминус—在UI中,在UI中,在кнопкинаэкране中。 Этобылопервоенашерешение,но,поочевиднымпричинам,еговпродакшнпускатьбылонельзя,таккакэтимвидеодолжныбылиделитьсяпользователи,иделитьсянессистемногопревью。
Итак,мыоказалисьвситуации,когдарешениенужнобылонаписатьснуля。 Совсемснуля。 Итак,давайтепосмотрим,какимобразомвайосможносоздатьсвоёвидео,изаписатьтудасвоик。 Всёдовольнопросто:
Нужносоздатьсущность,котораябудетзаписыватьфайлы – AVAssetWriter,добавитьвнеёвидеопоток – AVAssetWriterInput,исоздатьдляэтогопотокаадаптер,которыйбудетконвертироватьнашпиксельбуфервнеобходимыйпотокуформат – AVAssetWriterPixelBufferAdaptor。
Навсякийслучайнапоминаю,чтопиксельбуффер – этосущность,котораяпредставляетсобойкусокпамяти,вкоторомкаким-тообразомзаписаныданныедляпикселей。 Посути—низкоуровневоепредставлениекартинки。
Но…Какполучитьэтотпиксельбуффер? Решениепростое—在SCNViewестьзамечательнаяфункция.snapshot(),котораявозвращатUIImage,иметеление
Теперьнужноэтоделатькаждыйкадр。 Дляэтогомысоздаеёмдисплейлинк,которыйбудетнакаждыйкадрвызыватьколлбек,вкотороммыибудемвызыватьметод快照,исоздаватьизкартинкипиксельбуффер。 Всёпросто!
Авотинет。 Такоерешениедаженамощныхтелефонахвызываетжуткиелагиипросадкифпс。 Давайтезаймёмсяоптимизацией。
Допустим,намненужно60фпс。 Идажемыбудемдовольны25.Нокакэтопрощевсегосделать? Конечно,простовынестивсёэтонафоновыйпоток,темболеечтопоутверждениямразраоооииков,
Хм,лагатьсталоменьше,новидеопересталозаписываться…
Всёпросто。 Какговорится,еслиутебяестьпроблема,итыеёбудешьрешатьприпомощинесколькихооетое
Еслипопытатьсязаписатьпиксельбуферстаймстемпом,нижечемупоследнегозаписанноое-товсёв
Давайтетогданезаписыватьновыйбуфердотехпор,покапредыдущаязаписьнезакончится。
Хм,сталозначительнолучше。 Новсёравно,почемулагипоявилисьизначально?
Оказывается,функция.snapshot(),спомощьюкотороймыполучаемизображениесэкрана,накаждыйвызовсоздаётновыйрендерер,рисуеткадрснуля,ивозвращаетего,анетоизображение,котороеприсутствуетнаэкране。 Этоприводиткзабавнымэффектам,например,физическаясимуляцияпроисходитв2разабыстрее。
Нопогодите。 Зачеммыкаждыйразпытаемсяотрендеритьновыйкадр? Наверняка,где-томожнонайтитотбуфер,которыйвыводитсянаэкран。 Идействительно,доступктакомубуферуесть,ноонвесьманетривиален,идляэтогонамнужнеининининининиетель。
Ксожалению,напрямуюизSCNViewдобратьсядоMetal’анетакпросто,подовольнопростойпричине – вSceneKit’етипAPIможновыбратьсамому,ноеслизаглянутьподкапотипосмотретьна层,томожноувидеть,чтовкачественеговыступает, Metal’ом,— CAMetalLayer。
Ноитутнасждётнеудача:在CAMetalLayer中 Подразумевается,чтовывнегозапишетеданные,ивызоветеунегофункцию当前,котораяиотобразит。
Решение,насамомделе,существует。 Деловтом,чтопослеисчезаниясэкрананедеаллоцируется,以及лишьпомещаетсяобратновпул。 Действительно,зачемкаждыйразвыделятьпамять,еслидостаточно2х-3хбуферов:один,которыйпоказаннаэкране,второйдлярендеринга,итретий,например,дляпостпроцессинга,еслионувасесть。
Получается,послеотображениябуфера,данныеизнегоникуданепропадают,икнимооноспооо
И,еслимывнаследникеначнёмнакаждыйвызовnextDrawable()сохранятьего,мыполучимпочтито,чтонамнужн。 Проблемавтом,чтосохраненныйCAMetalDrawable —对的,是которыйпрямосейчасрисуетсяизображение。
Прыжоккреальномурешениюоченьпрост—мысохраняемитекущийдроуабл,ипредыдущий。
Ивотоно,готово,прямойдоступкпамятичерезCAMetalDrawable。
Чтоже,всеэтитрюкирадижутковатогофильтра?
Нуужнет! ВстатьепроARKitможнонайтиупоминаниетого,чтоизображениескамерыиспользуетнестандартноецветовоепространство,арасширенное,идажепредставиломатрицутрансформациицветовогопространства。 Нозачемзаниматьсятрансформацией,еслиможнопопробоватьзаписатьпрямовэтомформате。 Осталосьузнать—какойэтоформатиз60доступных…
Итутязанялсяперебором,изаписывалпо3видеовразныепотокисразнымиформатамисменяии。
Врезультате,примернонасороковомформатемыполучаемегоназвание。 Оказывается,этониктоиной,какkCVPixelFormatType_30RGBLEPackedWideGamut。 Какжеядоэтогонедогадался?
Номоярадостьпродолжаласьдопервоготестера。 Уменянебылослов。 Как? жжетолькочтопотратилкучувременинапоискправильногоформата。 Хорошо,чтопроблемалокализоваласьбыстро—图库照片6sи6s plus。 Практическисразупослеэвспомнил,чтодисплеисподдержкой广色域началиставитьтолькос7х。
ПоменявWideGamut在32RGBA和получаюработающуюзапись! Осталосьпонять,какопределять,чтодевайсподдерживает宽色域,таккакбываютещеайпадысразличнымивидамидисплея,ияподумал,чтонавернякаможноизсистемыдостатьэнамтипадисплея。 Покопавшисьвдокументациияегонашёл—在displayGamut或UITraitCollection’е中。
Отдавсборкутестерам,яполучилотнихприятныеновости—矢量图片ваникакакихлиболабелдажена
Вкачествезаключения,хочетсявамсказать—занимайтесь3Dграфикой! Унасвприложении,длякоторогодополненнаяреальностьнеявляетсяосновнымкейсомиспользования,людизавыходныеднягородапрошлиболее2000километров,посмотрелиболее3тысячобъектов,изаписалиболее1000видеосними! Представьтесебе,чтовысможетесделать,еслизаймётесьэтимсами。