Оглавление:

Портал дополненной реальности в перевернутом виде из очень странных дел: 10 шагов (с изображениями)
Портал дополненной реальности в перевернутом виде из очень странных дел: 10 шагов (с изображениями)

Видео: Портал дополненной реальности в перевернутом виде из очень странных дел: 10 шагов (с изображениями)

Видео: Портал дополненной реальности в перевернутом виде из очень странных дел: 10 шагов (с изображениями)
Видео: Секрет начальной заставки Барбоскиных 2024, Ноябрь
Anonim
Портал дополненной реальности в перевернутом виде из очень странных дел
Портал дополненной реальности в перевернутом виде из очень странных дел
Портал дополненной реальности в перевернутом виде из очень странных дел
Портал дополненной реальности в перевернутом виде из очень странных дел

В этом руководстве мы создадим мобильное приложение с дополненной реальностью для iPhone с порталом, который ведет к перевернутой игре Stranger Things. Вы можете зайти внутрь портала, обойти его и выйти. Все внутри портала можно увидеть только через портал, пока вы не войдете внутрь. Оказавшись внутри, все будет отображаться везде, пока вы не вернетесь в реальный мир. Мы будем использовать движок видеоигр Unity 3D с плагином Apple ARKit. Все программное обеспечение, которое мы будем использовать, можно загрузить и использовать бесплатно. Вам не нужно быть экспертом, чтобы следовать указаниям, мы проходим каждый шаг!

Шаг 1. Начните новый проект Unity

Начать новый проект Unity
Начать новый проект Unity

Прежде всего, загрузите Unity3D и обязательно установите файлы сборки для платформы IOS. Вам также необходимо загрузить Xcode и зарегистрироваться для получения бесплатной учетной записи разработчика Apple. Ваш iPhone также должен работать под управлением iOS 11 или выше. На сегодняшний день, 5 февраля 2018 года, iOS 11.3 отсутствует, но у xCode 9.2 еще нет файлов поддержки для нее. Поэтому, если вы используете самую последнюю версию IOS, обязательно загрузите последнюю бета-версию Xcode с Apple. Developer.com.

Когда у вас будут все необходимые программы, откройте Unity и начните новый проект, называйте его как хотите. Нам понадобится плагин Apple ARKit, чтобы мы могли использовать камеру нашего телефона для обнаружения земли и размещения объектов на полу. Давайте импортируем это сейчас, перейдя на вкладку Asset Store и поискав «ARKit». Вам нужно будет создать бесплатную учетную запись Unity, если у вас ее еще нет, затем нажмите «Импорт», чтобы получить плагин.

Перейдите в папку примеров в папке ARKit и найдите «UnityARKitScene». Дважды щелкните по нему, чтобы открыть. Мы собираемся использовать эту сцену в качестве отправной точки и отталкиваться от нее. Эта сцена по умолчанию позволит вам обнаружить землю, и когда вы коснетесь экрана, куб будет помещен в это положение.

Давайте сначала возьмем наши настройки сборки в квадрат, чтобы не забыть сделать это позже. Щелкните файл, создайте настройки и удалите все сцены из этого списка. Щелкните добавить открытые сцены, чтобы добавить нашу текущую. Последнее, что нам нужно настроить здесь, - это в настройках плеера перейти к идентификатору пакета, а формат этой строки - com. YourCompanyName. YourAppName, поэтому в моем случае я делаю что-то вроде com. MatthewHallberg. PortalTest.

Шаг 2: Настройте сцену

Настройте сцену
Настройте сцену

Сначала посмотрите налево и найдите игровой объект под названием «GeneratePlanes». Выделив это, посмотрите вправо и установите флажок, чтобы отключить его. Таким образом, у нас не будет уродливых синих квадратов, генерируемых, когда ARKit обнаруживает плоскость земли. Затем удалите игровой объект «RandomCube», потому что мы не хотим видеть его в нашей сцене.

Теперь нам нужно сначала создать дверной проем нашего портала. Удалите куб, который является дочерним по отношению к HitCubeParent. Щелкните правой кнопкой мыши и выберите создать пустой игровой объект. Переименуйте его в «Портал». Теперь щелкните этот объект правой кнопкой мыши и создайте куб, это сделает его дочерним по отношению к порталу. Переименуйте его в PostLeft, и это будет левый пост нашего портала. Масштабируйте его так, чтобы x был равен 1, y был равен 28, а z был равен единице. Сделайте то же самое с правильным постом. Теперь создайте верхнюю стойку и увеличьте y до 14. Поверните ее в сторону и переместите так, чтобы она соединила другие стойки. Сделайте масштаб всего портала 1,3 x 1,4 x 1.

Зайдите в Google и введите текстуру дерева или коры. Загрузите одно из этих изображений и перетащите его в папку с ресурсами в Unity. Теперь перетащите это изображение на все сообщения вашего портала.

Снова щелкните объект «Портал» и справа щелкните добавить компонент. Добавьте к нему скрипт UnityARHitTestExample. Там есть пустой слот для «Hit Transform», перетащите объект «HitCubeParent» в этот слот.

Шаг 3: сделаем несколько частиц

Сделаем несколько частиц
Сделаем несколько частиц

Теперь мы собираемся использовать систему частиц Unity, чтобы создать эффект дыма и плавающих частиц внутри нашего портала. Перейдите в Assets в верхней строке меню, стандартные активы и импортируйте системы частиц.

Создайте два пустых игровых объекта внутри своего портала и назовите один «SmokeParticles», а другой «FloatingParticles».

Добавьте к частицам дыма компонент системы частиц.

У этого компонента есть множество опций, но нам нужно изменить только пару.

Измените начальный цвет на темно-синий с прозрачностью около 50%. Сделайте скорость излучения 100. Внутри формы сделайте радиус 0,01. В части рендеринга внизу измените минимальный размер на 0,8 и максимальный размер на 5. В компоненте материала просто выберите материал дыма из списка, но мы собираемся изменить это позже.

Теперь добавьте систему частиц к игровому объекту с плавающими частицами и установите излучение на 500. Установите время начала действия на 2, радиус на 10, минимальный размер частицы на 0,01 и максимальный размер частицы на 0,015. На данный момент установите материал для частиц по умолчанию.

Наконец, возьмите оба игровых объекта, поверните их на 90 градусов по оси x и поднимите в воздух, чтобы они падали в дверной проем портала.

Шаг 4. Замедление частиц

Замедление частиц
Замедление частиц

Поскольку мы хотим, чтобы эти частицы покрывали большую площадь, но при этом двигались медленно, нам нужно создать нашу собственную функцию-образец. Итак, щелкните правой кнопкой мыши папку с ресурсами и создайте новый сценарий C # и назовите его «ParticleSample». Скопируйте и вставьте этот код:

using System. Collections;

using System. Collections. Generic; using UnityEngine; публичный класс ParticleSample: MonoBehaviour {частный ParticleSystem ps; // Используйте это для инициализации void Start () {ps = GetComponent (); StartCoroutine (SampleParticleRoutine ()); } IEnumerator SampleParticleRoutine () {var main = ps.main; main.simulationSpeed = 1000f; ps. Play (); yield return новый WaitForSeconds (.1f); main.simulationSpeed =.05f; }}

Теперь перетащите этот скрипт на каждый игровой объект вашей системы частиц.

Шаг 5: Создание портала

Создание портала!
Создание портала!

Теперь нам нужно создать портал, поэтому щелкните правой кнопкой мыши на игровом объекте портала и создайте четырехугольник. Измените масштаб квадрата так, чтобы он покрыл весь портал, он станет нашим окном портала. Первое, что нам нужно добавить к нему, это шейдер портала, он будет отображать только объекты с другим конкретным шейдером на них. Щелкните правой кнопкой мыши папку с ресурсами и создайте новый неосвещенный шейдер. Удалите все и вставьте этот код:

Шейдер "Portal / portalWindow"

{SubShader {Zwrite off Colormask 0 cull off Stencil {Ref 1 Pass replace} Pass {}}}

Щелкните правой кнопкой мыши в иерархии и создайте новый материал, назовите его PortalWindowMat, в раскрывающемся списке для этого материала найдите раздел портала и выберите окно портала. Перетащите этот материал на свой портал.

Шаг 6: шейдеры частиц

Шейдеры частиц
Шейдеры частиц

Снова щелкните правой кнопкой мыши папку с ресурсами и создайте новый шейдер. Нам нужно создать шейдеры для частиц, которые входят в портал. Замените весь код следующим:

Шейдер "Портал / Частицы" {

Свойства {_TintColor («Цвет оттенка», Цвет) = (0,5, 0,5, 0,5, 0,5) _MainTex («Текстура частиц», 2D) = «белый» {} _InvFade («Фактор мягких частиц», диапазон (0,01, 3,0)) = 1.0 _Stencil ("stencil", int) = 6} Категория {Теги {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" "PreviewType" = "Plane"} Blend SrcAlpha OneMinusSrcAlpha ColorMask RGB Cull Off Освещение выключено ZWrite Off SubShader {Stencil {Ref 1 Comp [_Stencil]} Передайте {CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 2.0 #pragma multi_compile_particles #pragma multi_compile_fog #include "_SampleCG.cg" fixed4 _TintColor; struct appdata_t {вершина float4: ПОЗИЦИЯ; fixed4 цвет: ЦВЕТ; float2 texcoord: TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID}; struct v2f {вершина float4: SV_POSITION; fixed4 цвет: ЦВЕТ; float2 texcoord: TEXCOORD0; UNITY_FOG_COORDS (1) #ifdef SOFTPARTICLES_ON float4 projPos: TEXCOORD2; #endif UNITY_VERTEX_OUTPUT_STEREO}; float4 _MainTex_ST; v2f верт (appdata_t v) {v2f o; UNITY_SETUP_INSTANCE_ID (v); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO (o); o.vertex = UnityObjectToClipPos (v.vertex); #ifdef SOFTPARTICLES_ON o.projPos = ComputeScreenPos (o.vertex); COMPUTE_EYEDEPTH (o.projPos.z); #endif o.color = v.color * _TintColor; o.texcoord = TRANSFORM_TEX (v.texcoord, _MainTex); UNITY_TRANSFER_FOG (o, o.vertex); return o; } UNITY_DECLARE_DEPTH_TEXTURE (_CameraDepthTexture); float _InvFade; fixed4 frag (v2f i): SV_Target {#ifdef SOFTPARTICLES_ON float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ (_CameraDepthTexture, UNITY_PROJ_COORD (i.projPos))); float partZ = i.projPos.z; float fade = saturate (_InvFade * (sceneZ-partZ)); i.color.a * = исчезать; #endif fixed4 col = 2.0f * i.color * tex2D (_MainTex, i.texcoord); UNITY_APPLY_FOG (i.fogCoord, столбец); return col; } ENDCG}}}}

Создайте два новых материала, один под названием portalSmoke, а другой под названием portalParticles.

Для каждого выберите этот шейдер в раскрывающемся списке порталов, частиц. Для частиц дыма выберите текстуру дыма, а для частиц выберите текстуру частиц. Измените цвет дыма на темно-синий с прозрачностью около 50%. Перейдите к компоненту рендеринга каждой системы частиц на вашем портале и выберите соответствующие материалы, которые мы только что создали.

Шаг 7: Создайте Skybox

Создайте Skybox
Создайте Skybox

Теперь, чтобы действительно создать перевернутый вид, нам нужно окрасить все в темно-синий цвет. Для этого мы будем использовать прозрачный скайбокс, поэтому создайте новый шейдер и вставьте этот код:

Шейдер "Portal / portalSkybox" {

Свойства {_Tint ("Цвет оттенка", Color) = (.5,.5,.5,.5) [Gamma] _Exposure ("Exposure", Range (0, 8)) = 1.0 _Rotation ("Rotation", Range (0, 360)) = 0 [NoScaleOffset] _Tex ("Cubemap (HDR)", Cube) = "серый" {} _Stencil ("StencilNum", int) = 6} SubShader {Tags {"Queue" = "Фон" "RenderType" = "Background" "PreviewType" = "Skybox"} Cull Off ZWrite Off Blend SrcAlpha OneMinusSrcAlpha Stencil {Ref 1 Comp [_Stencil]} Передать {CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 2.0Colder #inGclude.cginc "samplerCUBE _Tex; half4 _Tex_HDR; half4 _Tint; половина _Exposure; float _Rotation; float3 RotateAroundYInDegrees (вершина float3, градусы с плавающей запятой) {альфа с плавающей точкой = градусы * UNITY_PI / 180.0; float sina, cosa; синко (альфа, сина, коза); float2x2 m = float2x2 (cosa, -sina, sina, cosa); вернуть float3 (mul (m, vertex.xz), vertex.y).xzy; } struct appdata_t {вершина float4: ПОЗИЦИЯ; UNITY_VERTEX_INPUT_INSTANCE_ID}; struct v2f {вершина float4: SV_POSITION; float3 texcoord: TEXCOORD0; UNITY_VERTEX_OUTPUT_STEREO}; v2f верт (appdata_t v) {v2f o; UNITY_SETUP_INSTANCE_ID (v); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO (o); float3 rotated = RotateAroundYInDegrees (v.vertex, _Rotation); o.vertex = UnityObjectToClipPos (повернутый); o.texcoord = v.vertex.xyz; return o; } fixed4 frag (v2f i): SV_Target {half4 tex = texCUBE (_Tex, i.texcoord); half3 c = DecodeHDR (tex, _Tex_HDR); c = c * _Tint.rgb * unity_ColorSpaceDouble.rgb; c * = _Exposure; вернуть half4 (c,.5); } ENDCG}} Откл. Откл.}

Теперь создайте новый материал скайбокса, назовите его «PortalSkybox» и выберите этот шейдер portalSkybox в меню портала. Перейдите в Window, Lighting, вверху и выберите этот скайбокс, который мы только что создали. Подойдите к основной камере и установите флажки для скайбокса. Пока мы здесь, давайте добавим некоторые компоненты в нашу камеру, чтобы мы могли обнаруживать столкновения. Добавьте в камеру компонент твердого тела и снимите флажок использовать гравитацию. Добавьте коллайдер коробки и отметьте триггер. Установите размер коллайдера бокса 0,5 x 1 x 4. Установите плоскость отсечения камеры на 0,01.

Шаг 8: логика портала

Портальная логика
Портальная логика

Последнее, что нам нужно сделать, это создать логику, управляющую нашим порталом. Создайте новый сценарий C # и назовите его PortalController.

using System. Collections;

using System. Collections. Generic; using UnityEngine; пространство имен UnityEngine. XR.iOS {открытый класс PortalController: MonoBehaviour {общедоступные материалы материалы; общедоступный MeshRenderer meshRenderer; общедоступный UnityARVideo UnityARVideo; частный bool isInside = false; private bool isOutside = true; // Используйте это для инициализации void Start () {OutsidePortal (); } void OnTriggerStay (Collider col) {Vector3 playerPos = Camera.main.transform.position + Camera.main.transform.forward * (Camera.main.nearClipPlane * 4); если (transform. InverseTransformPoint (playerPos).z <= 0) {если (isOutside) {isOutside = false; isInside = true; InsidePortal (); }} еще {если (isInside) {isInside = false; isOutside = true; OutsidePortal (); }}} void OutsidePortal () {StartCoroutine (DelayChangeMat (3)); } void InsidePortal () {StartCoroutine (DelayChangeMat (6)); } IEnumerator DelayChangeMat (int stencilNum) {UnityARVideo.shouldRender = false; yield return new WaitForEndOfFrame (); meshRenderer.enabled = false; foreach (Мат материала в материалах) {mat. SetInt ("_Stencil", stencilNum); } yield return new WaitForEndOfFrame (); meshRenderer.enabled = true; UnityARVideo.shouldRender = true; }}}

Перетащите этот новый скрипт в окно вашего портала. Это будет перемещать нас в портал и обратно всякий раз, когда коллайдер на нашей камере сталкивается с окном портала. Теперь в функции, которая изменяет все материалы, мы говорим плагину ARkit не отображать кадр, поэтому перейдите к основной камере и откройте скрипт UnityARVideo. Создайте публичный bool shouldRender вверху и установите для него значение true. Внизу в функции OnPreRender () оберните все в оператор if, где все внутри будет запускаться только в том случае, если shouldRender истинно. Весь сценарий должен выглядеть так:

используя Систему;

using System. Runtime. InteropServices; using UnityEngine; с использованием UnityEngine. Rendering; пространство имен UnityEngine. XR.iOS {открытый класс UnityARVideo: MonoBehaviour {общедоступный материал m_ClearMaterial; [HideInInspector] public bool shouldRender = true; частный CommandBuffer m_VideoCommandBuffer; частный Texture2D _videoTextureY; частный Texture2D _videoTextureCbCr; частный Matrix4x4 _displayTransform; private bool bCommandBufferInitialized; public void Start () {UnityARSessionNativeInterface. ARFrameUpdatedEvent + = UpdateFrame; bCommandBufferInitialized = false; } void UpdateFrame (UnityARCamera cam) {_displayTransform = new Matrix4x4 (); _displayTransform. SetColumn (0, cam.displayTransform.column0); _displayTransform. SetColumn (1, cam.displayTransform.column1); _displayTransform. SetColumn (2, cam.displayTransform.column2); _displayTransform. SetColumn (3, cam.displayTransform.column3); } void InitializeCommandBuffer () {m_VideoCommandBuffer = новый CommandBuffer (); m_VideoCommandBuffer. Blit (null, BuiltinRenderTextureType. CurrentActive, m_ClearMaterial); GetComponent (). AddCommandBuffer (CameraEvent. BeforeForwardOpaque, m_VideoCommandBuffer); bCommandBufferInitialized = true; } void OnDestroy () {GetComponent (). RemoveCommandBuffer (CameraEvent. BeforeForwardOpaque, m_VideoCommandBuffer); UnityARSessionNativeInterface. ARFrameUpdatedEvent - = UpdateFrame; bCommandBufferInitialized = false; } #if! UNITY_EDITOR public void OnPreRender () {if (shouldRender) {ARTextureHandles handles = UnityARSessionNativeInterface. GetARSessionNativeInterface (). GetARVideoTextureHandles (); если (handles.textureY == System. IntPtr. Zero || handles.textureCbCr == System. IntPtr. Zero) {возврат; } если (! bCommandBufferInitialized) {InitializeCommandBuffer (); } Разрешение currentResolution = Screen.currentResolution; // Текстура Y if (_videoTextureY == null) {_videoTextureY = Texture2D. CreateExternalTexture (currentResolution.width, currentResolution.height, TextureFormat. R8, false, false, (System. IntPtr) handles.textureY); _videoTextureY.filterMode = FilterMode. Bilinear; _videoTextureY.wrapMode = TextureWrapMode. Repeat; m_ClearMaterial. SetTexture ("_ textureY", _videoTextureY); } // Текстура CbCr if (_videoTextureCbCr == null) {_videoTextureCbCr = Texture2D. CreateExternalTexture (currentResolution.width, currentResolution.height, TextureFormat. RG16, false, false, (System. IntPtr) handles.textureCbCr); _videoTextureCbCr.filterMode = FilterMode. Bilinear; _videoTextureCbCr.wrapMode = TextureWrapMode. Repeat; m_ClearMaterial. SetTexture ("_ textureCbCr", _videoTextureCbCr); } _videoTextureY. UpdateExternalTexture (handles.textureY); _videoTextureCbCr. UpdateExternalTexture (handles.textureCbCr); m_ClearMaterial. SetMatrix ("_ DisplayTransform", _displayTransform); }} #else public void SetYTexure (Texture2D YTex) {_videoTextureY = YTex; } public void SetUVTexure (Texture2D UVTex) {_videoTextureCbCr = UVTex; } public void OnPreRender () {если (! bCommandBufferInitialized) {InitializeCommandBuffer (); } m_ClearMaterial. SetTexture ("_ textureY", _videoTextureY); m_ClearMaterial. SetTexture ("_ textureCbCr", _videoTextureCbCr); m_ClearMaterial. SetMatrix ("_ DisplayTransform", _displayTransform); } #endif}}

Шаг 9: почти готово

Почти сделано!
Почти сделано!

Наконец, когда мы щелкаем по экрану и размещаем портал, мы хотим, чтобы он всегда был обращен к нам. Для этого перейдите к скрипту «UnityARHitTestExample» на портале. Замени все внутри на это:

используя Систему;

using System. Collections. Generic; пространство имен UnityEngine. XR.iOS {открытый класс UnityARHitTestExample: MonoBehaviour {общедоступное преобразование m_HitTransform; публичный поплавок maxRayDistance = 30.0f; общедоступный LayerMask collisionLayer = 1 <0) {foreach (var hitResult в hitResults) {Debug. Log ("Попал!"); m_HitTransform.position = UnityARMatrixOps. GetPosition (hitResult.worldTransform); m_HitTransform.rotation = UnityARMatrixOps. GetRotation (hitResult.worldTransform); Debug. Log (string. Format ("x: {0: 0. ######} y: {1: 0. ######} z: {2: 0. ###### } ", m_HitTransform.position.x, m_HitTransform.position.y, m_HitTransform.position.z)); Vector3 currAngle = transform.eulerAngles; transform. LookAt (Camera.main.transform); transform.eulerAngles = новый Vector3 (currAngle.x, transform.eulerAngles.y, currAngle.z); вернуть истину; }} return false; } // Обновление вызывается один раз за кадр void Update () {#if UNITY_EDITOR // мы будем использовать этот скрипт только на стороне редактора, хотя нет ничего, что могло бы помешать ему работать на устройстве if (Input. GetMouseButtonDown (0)) {Ray ray = Camera.main. ScreenPointToRay (Input.mousePosition); RaycastHit Hit; // мы попытаемся поразить один из игровых объектов коллайдера плоскости, который был сгенерирован плагином // эффективно аналогично вызову HitTest с ARHitTestResultType. ARHitTestResultTypeExistingPlaneUsingExtent if (Physics. Raycast (ray, out hit, maxRayDistance, collisionLayer)) {// мы собираемся получить позицию из точки контакта m_HitTransform.position = hit.point; Debug. Log (string. Format ("x: {0: 0. ######} y: {1: 0. ######} z: {2: 0. ###### } ", m_HitTransform.position.x, m_HitTransform.position.y, m_HitTransform.position.z)); // и поворот из преобразования коллайдера плоскости m_HitTransform.rotation = hit.transform.rotation; }} #else if (Input.touchCount> 0 && m_HitTransform! = null) {var touch = Input. GetTouch (0); if (touch.phase == TouchPhase. Began || touch.phase == TouchPhase. Moved) {var screenPosition = Camera.main. ScreenToViewportPoint (touch.position); Точка ARPoint = новая точка ARPoint {x = screenPosition.x, y = screenPosition.y}; // Приоритетность типы reults ARHitTestResultType = {resultTypes ARHitTestResultType. ARHitTestResultTypeExistingPlaneUsingExtent, // если вы хотите использовать бесконечные самолеты использовать это: //ARHitTestResultType. ARHitTestResultTypeExistingPlane, ARHitTestResultType. ARHitTestResultTypeHorizontalPlane, ARHitTestResultType. ARHitTestResultTypeFeaturePoint}; foreach (ARHitTestResultType resultType в resultTypes) {if (HitTestWithResultType (point, resultType)) {return; }}}} #endif}}}

Шаг 10: Установите приложение на свой телефон

Установите приложение на свой телефон!
Установите приложение на свой телефон!

Наконец мы закончили. Зайдите в файл, выберите настройки сборки и нажмите build. Откройте Xcode и выберите папку, созданную при сборке. Выберите команду разработчиков и установите приложение на свой телефон! Вы можете изменить цвета частиц и скайбокса в соответствии с вашими потребностями. Дайте мне знать в комментариях, если у вас есть какие-либо вопросы, и спасибо, что посмотрели!

Рекомендуемые: