Taula de continguts:

Portal d'AR al revés de coses més estranyes: 10 passos (amb imatges)
Portal d'AR al revés de coses més estranyes: 10 passos (amb imatges)

Vídeo: Portal d'AR al revés de coses més estranyes: 10 passos (amb imatges)

Vídeo: Portal d'AR al revés de coses més estranyes: 10 passos (amb imatges)
Vídeo: И ЭТО ТОЖЕ ДАГЕСТАН? Приключения в долине реки Баараор. БОЛЬШОЙ ВЫПУСК (Путешествие по Дагестану #3) 2024, Desembre
Anonim
Portal d'AR al revés de coses més estranyes
Portal d'AR al revés de coses més estranyes
Portal d'AR al revés de coses més estranyes
Portal d'AR al revés de coses més estranyes

Aquest instructable passarà per la creació d'una aplicació mòbil de realitat augmentada per a l'iPhone amb un portal que condueix al revés des de Stranger Things. Podeu entrar al portal, passejar i tornar a sortir. Tot el que hi ha dins del portal només es pot veure a través del portal fins que no passeu per dins. Un cop a dins, tot es renderitzarà arreu, fins que tornis al món real. Utilitzarem el motor de videojocs Unity 3D amb el connector Apple ARKit. Tot el programari que utilitzarem es pot descarregar i utilitzar de forma gratuïta. No cal que sigueu un expert per seguir-ho, anirem fent tots els passos.

Pas 1: inicieu un nou projecte Unity

Inicieu un nou projecte Unity
Inicieu un nou projecte Unity

En primer lloc, descarregueu Unity3D i assegureu-vos d’instal·lar els fitxers de compilació de la plataforma IOS. També haureu de descarregar Xcode i registrar-vos per obtenir un compte gratuït per a desenvolupadors d'Apple. El vostre iPhone també haurà d’executar iOS 11 o superior. A partir d’avui 5 de febrer de 2018, iOS 11.3 està fora, però xCode 9.2 encara no disposa de fitxers de suport. Per tant, si teniu la versió més recent d’IOS, assegureu-vos de descarregar la versió beta més recent de Xcode des d’Apple. Developer.com.

Un cop tingueu tots els programes necessaris, obriu Unity i inicieu un nou projecte, anomeneu-lo com vulgueu. Necessitarem el connector Apple ARKit perquè puguem utilitzar la càmera del nostre telèfon per detectar el terra i col·locar objectes a terra. Importem-ho ara anant a la pestanya Asset Store i cercant "ARKit". Haureu de crear un compte Unity gratuït si encara no en teniu, i després feu clic a Importa per obtenir el connector.

Aneu a la carpeta d'exemples de la carpeta ARKit i cerqueu "UnityARKitScene". Feu doble clic per obrir-lo. Utilitzarem aquesta escena com a punt de partida i partirem d’aquí. Aquesta escena per defecte us permetrà detectar el terra i, quan toqueu la pantalla, es col·locarà un cub en aquesta posició.

Primer deixem els nostres paràmetres de construcció al quadrat, de manera que no ens oblidem de fer-ho més tard. Feu clic a Arxiu, creeu la configuració i elimineu totes les escenes d'aquesta llista. Feu clic a Afegeix escenes obertes per afegir la nostra actual. L'últim que hem de configurar aquí és que a la configuració dels reproductors aneu a identificador de paquet i el format d'aquesta cadena és com. YourCompanyName. YourAppName, de manera que en el meu cas faig alguna cosa com com. MatthewHallberg. PortalTest.

Pas 2: configureu l'escena

Configureu l'escena
Configureu l'escena

Primer mireu a l'esquerra i cerqueu l'objecte del joc anomenat "GeneratePlanes". Amb això ressaltat, mireu cap a la dreta ara i feu clic a la casella de selecció per desactivar-lo. D’aquesta manera no es generen els lletges quadres blaus quan ARKit detecta un pla de terra. A continuació, suprimiu l'objecte de joc "RandomCube" perquè no volem veure-ho a la nostra escena.

Ara hem de crear primer el portal d’entrada. Elimineu el cub que és fill del "HitCubeParent". Feu clic amb el botó dret i trieu crear un objecte de joc buit. Canvieu el nom de "Portal". Ara feu clic amb el botó dret sobre aquest objecte i creeu un cub, cosa que farà que sigui un fill del portal. Canvieu el nom de "PostLeft" i aquest serà el missatge esquerre del nostre portal. Escaleu-lo de manera que la x sigui 1 la y sigui 28 i la z sigui una. Feu el mateix per al missatge correcte. Ara creeu el pal superior i escaleu la y a 14. Gireu-lo cap als costats i moveu-lo de manera que connecti els altres pals. Feu que l’escala del portal siga 1,3 x 1,4 x 1.

Aneu a Google i escriviu textura de fusta o d’escorça. Baixeu-vos una d'aquestes imatges i arrossegueu-la a la carpeta de recursos a Unity. Ara arrossegueu aquesta imatge a totes les publicacions del vostre portal.

Feu clic de nou a l'objecte "Portal" i feu clic a Afegeix component a la dreta. Afegiu-hi l'script "UnityARHitTestExample". Allà hi ha una ranura buida per a "Hit Transform", arrossegueu l'objecte "HitCubeParent" a aquesta ranura.

Pas 3: fem algunes partícules

Fem algunes partícules
Fem algunes partícules

Ara utilitzarem el sistema Unity Particle per produir un efecte de fum i partícules flotants a l'interior del nostre portal. Aneu a Recursos a la barra de menú superior, recursos estàndard i sistemes d'importació de partícules.

Creeu dos objectes de joc buits dins del portal i truqueu un a "SmokeParticles" i l'altre a "FloatingParticles".

Afegiu un component del sistema de partícules a les partícules de fum.

Aquest component té un munt d’opcions, però només cal canviar-ne un parell.

Canvieu el color inicial a un blau fosc amb un 50% de transparència. Feu la taxa d’emissió 100. Dins de la forma, feu el radi 0,01. A la part del renderitzador de la part inferior, canvieu la mida mínima a.8 i la mida màxima a 5. Al component de material, només heu de triar el material de fum de la llista, però ho canviarem més endavant.

Afegiu ara un sistema de partícules a l'objecte de joc de partícules flotants i configureu l'emissió a 500. Establiu la vida útil inicial a 2, el radi a 10, la mida mínima de partícula a 0,01 i la mida màxima de partícula a 0,015. Estableix el material com a partícula per defecte per ara.

Finalment, agafeu els dos objectes del joc i gireu-los 90 graus sobre la x i aixequeu-los a l’aire perquè estiguin emetent cap a la porta del portal.

Pas 4: Alentir les partícules

Alentir les partícules
Alentir les partícules

Com que volem que aquestes partícules cobreixin una àrea gran però que també es moguin lentament, hem de crear la nostra pròpia funció de mostra. Per tant, feu clic amb el botó dret a la carpeta de recursos i creeu un script C # nou i anomeneu-lo "ParticleSample". Copieu i enganxeu aquest codi:

utilitzant System. Collections;

utilitzant System. Collections. Generic; utilitzant UnityEngine; classe pública ParticleSample: MonoBehaviour {private ParticleSystem ps; // Utilitzeu això per a la inicialització void Start () {ps = GetComponent (); StartCoroutine (SampleParticleRoutine ()); } IEnumerator SampleParticleRoutine () {var main = ps.main; main.simulationSpeed = 1000f; ps. Play (); rendibilitat retorna nous WaitForSeconds (.1f); main.simulationSpeed =.05f; }}

Ara arrossegueu aquest script a cadascun dels objectes del joc del vostre sistema de partícules.

Pas 5: Creació del portal

Creació del portal
Creació del portal

Ara hem de crear el portal, així que feu clic amb el botó dret a l’objecte del joc del portal i creeu un quad. Escaleu el quad de manera que cobreixi tot el portal, aquest esdevindrà la nostra finestra del portal. El primer que li hem d’afegir és el sombreador del portal, que només representarà objectes amb un altre sombreador específic. Feu clic amb el botó dret a la carpeta de recursos i creeu un nou ombrejat il·luminat. Elimineu tot el que hi ha i enganxeu-lo en aquest codi:

Shader "Portal / portalWindow"

{SubShader {Zwrite off Colormask 0 eliminat Stencil {Ref 1 Passar substituir} Passar {}}}

Feu clic amb el botó dret a la jerarquia i creeu un material nou, anomeneu-lo PortalWindowMat, al menú desplegable d'aquest material, trobeu la secció del portal i trieu la finestra del portal. Arrossegueu aquest material al quad del portal.

Pas 6: ombres de partícules

Ombres de partícules
Ombres de partícules

Torneu a fer clic amb el botó dret a la carpeta de recursos i creeu un nou ombrejat. Hem de fer ombres per a les partícules que van a l’interior del portal. Substitueix tot el codi per això:

"Portal / Partícules" de Shader {

Propietats {_TintColor ("Tint Color", Color) = (0,5, 0,5, 0,5, 0,5) _MainTex ("Particle Texture", 2D) = "blanc" {} _InvFade ("Factor de partícules suaus", rang (0,01, 3,0)) = 1.0 _Stencil ("stencil", int) = 6} Categoria {Etiquetes {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" "PreviewType" = "Plane"} Blend SrcAlpha OneMinusSrcAlpha ColorMask RGB Cull Off Lighting Off ZWrite Off SubShader {Stencil {Ref 1 Comp [_Stencil]} Pass {CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 2.0 #pragma multi_compile_particles #pragma multi_compile_fog #include "UnityCG.cginc" sampler fixed4 _TintColor; struct appdata_t {float4 vertex: POSITION; fix4 color: COLOR; float2 texcoord: TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID}; struct v2f {float4 vertex: SV_POSITION; fix4 color: COLOR; float2 texcoord: TEXCOORD0; UNITY_FOG_COORDS (1) #ifdef SOFTPARTICLES_ON float4 projPos: TEXCOORD2; #endif UNITY_VERTEX_OUTPUT_STEREO}; float4 _MexTex_ST; v2f vert (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); tornar 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))); part flotant Z = i.projPos.z; float fade = saturar (_InvFade * (sceneZ-partZ)); i.color.a * = esvair; #endif fixed4 col = 2.0f * i.color * tex2D (_MainTex, i.texcoord); UNITY_APPLY_FOG (i.fogCoord, col); tornar col; } ENDCG}}}}

Creeu dos materials nous, un anomenat portalSmoke i un altre anomenat portalParticles.

Per a cadascun, trieu aquest ombrejat, des del menú desplegable, en portals, partícules. Per a les partícules de fum, escolliu una textura de fum i per a les partícules, escolliu la textura de les partícules. Canvieu el color del fum a un blau més fosc amb aproximadament un 50% de transparència. Aneu al component de representació de cada sistema de partícules del vostre portal i trieu els materials respectius que acabem de crear.

Pas 7: creeu el Skybox

Creeu el Skybox
Creeu el Skybox

Ara, per crear realment el tipus d’aspecte capgirat, hem de tenyir-ho tot de color blau fosc. Per a això utilitzarem un skybox transparent, així que feu un nou ombrejat i enganxeu-lo en aquest codi:

Shader "Portal / portalSkybox" {

Propietats {_Tint ("Tint Color", Color) = (.5,.5,.5,.5) [Gamma] _Exposure ("Exposure", Range (0, 8)) = 1.0 _Rotation ("Rotation", Range (0, 360)) = 0 [NoScaleOffset] _Tex ("Cubemap (HDR)", Cube) = "gris" {} _Stencil ("StencilNum", int) = 6} SubShader {Etiquetes {"Queue" = "Fons" "RenderType" = "Fons" "PreviewType" = "Skybox"} Cull Off ZWrite Off Blend SrcAlpha OneMinusSrcAlpha Stencil {Ref 1 Comp [_Stencil]} Pass {CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 2.0 #include "UnityCG.cginc "samplerCUBE _Tex; half4 _Tex_HDR; half4 _Tint; meitat _Exposició; float _Rotació; float3 RotateAroundYInDegrees (float3 vèrtex, float graus) {float alfa = graus * UNITY_PI / 180.0; float sina, cosa; sincos (alfa, sina, cosa); float2x2 m = float2x2 (cosa, -sina, sina, cosa); return float3 (mul (m, vertex.xz), vertex.y).xzy; } struct appdata_t {float4 vertex: POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID}; struct v2f {float4 vertex: SV_POSITION; float3 texcoord: TEXCOORD0; UNITY_VERTEX_OUTPUT_STEREO}; v2f vert (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 (girat); o.texcoord = v.vertex.xyz; tornar o; } fixed4 frag (v2f i): SV_Target {half4 tex = texCUBE (_Tex, i.texcoord); half3 c = DecodeHDR (tex, _Tex_HDR); c = c * _Tint.rgb * units_ColorSpaceDouble.rgb; c * = _Exposició; retorn mitja4 (c, 0,5); } ENDCG}} Fallback Off}

Ara creeu un nou material de skybox, anomeneu-lo "PortalSkybox" i trieu aquest ombrador de portalSkybox al menú del portal. Aneu a Finestra, Il·luminació, a la part superior i trieu aquest skybox que acabem de crear. Aneu a la càmera principal i configureu els senyals nets a skybox. Mentre estem aquí, permet afegir alguns components a la càmera perquè puguem detectar col·lisions. Afegiu un component de cos rígid a la càmera i desmarqueu l'ús de la gravetat. Afegiu un col·lisionador de caixes i comproveu que és activador. Feu que els col·lisionadors de caixes tinguin una mida de.5 x 1 x 4. Establiu el pla de retall de la càmera a.01.

Pas 8: Lògica del portal

Lògica del portal
Lògica del portal

L’últim que hem de fer és crear la lògica que controla el nostre portal. Creeu un script C # nou i anomeneu-lo PortalController.

utilitzant System. Collections;

utilitzant System. Collections. Generic; utilitzant UnityEngine; espai de noms UnityEngine. XR.iOS {class públic PortalController: MonoBehaviour {public Material materials; public MeshRenderer meshRenderer; UnityARVideo públic UnityARVideo; private bool isInside = false; private bool isOutside = true; // Utilitzeu això per a la inicialització void Start () {OutsidePortal (); } void OnTriggerStay (Collider col) {Vector3 playerPos = Camera.main.transform.position + Camera.main.transform.forward * (Camera.main.nearClipPlane * 4); if (transform. InverseTransformPoint (playerPos).z <= 0) {if (isOutside) {isOutside = false; isInside = true; InsidePortal (); }} else {if (isInside) {isInside = false; isOutside = true; OutsidePortal (); }}} void OutsidePortal () {StartCoroutine (DelayChangeMat (3)); } void InsidePortal () {StartCoroutine (DelayChangeMat (6)); } IEnumerator DelayChangeMat (int stencilNum) {UnityARVideo.shouldRender = false; rendibilitat torna nova WaitForEndOfFrame (); meshRenderer.enabled = fals; foreach (Material estora en materials) {mat. SetInt ("_Stencil", stencilNum); } render return new WaitForEndOfFrame (); meshRenderer.enabled = cert; UnityARVideo.shouldRender = cert; }}}

Arrossegueu aquest nou script a la finestra del portal. Això ens farà passar i entrar del portal sempre que el col·lisionador de la càmera xoqui amb la finestra del portal. Ara, a la funció que canvia tots els materials, li diem al connector ARkit que no renderitzi el marc, així que aneu a la càmera principal i obriu l'script UnityARVideo. Creeu un boolè públic shouldRender a la part superior i establiu-lo igual a true. A la funció OnPreRender (), envolteu-ho tot en una sentència if, on tot el que hi ha dins només s’executarà si shouldRender és cert. Tot el guió ha de tenir aquest aspecte:

utilitzant el sistema;

utilitzant System. Runtime. InteropServices; utilitzant UnityEngine; utilitzant UnityEngine. Rendering; espai de noms UnityEngine. XR.iOS {classe pública UnityARVideo: MonoBehaviour {public Material m_ClearMaterial; [HideInInspector] public bool shouldRender = true; private CommandBuffer m_VideoCommandBuffer; private Texture2D _videoTextureY; private Texture2D _videoTextureCbCr; privat Matrix4x4 _displayTransform; private bool bCommandBufferInitialized; public void Start () {UnityARSessionNativeInterface. ARFrameUpdatedEvent + = UpdateFrame; bCommandBufferInitialized = fals; } 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 = new CommandBuffer (); m_VideoCommandBuffer. Blit (nul, BuiltinRenderTextureType. CurrentActive, m_ClearMaterial); GetComponent (). AddCommandBuffer (CameraEvent. BeforeForwardOpaque, m_VideoCommandBuffer); bCommandBufferInitialized = cert; } void OnDestroy () {GetComponent (). RemoveCommandBuffer (CameraEvent. BeforeForwardOpaque, m_VideoCommandBuffer); UnityARSessionNativeInterface. ARFrameUpdatedEvent - = UpdateFrame; bCommandBufferInitialized = fals; } #if! UNITY_EDITOR public void OnPreRender () {if (shouldRender) {ARTextureHandles handles = UnityARSessionNativeInterface. GetARSessionNativeInterface (). GetARVideoTextureHandles (); if (handles.textureY == System. IntPtr. Zero || handles.textureCbCr == System. IntPtr. Zero) {return; } if (! bCommandBufferInitialized) {InitializeCommandBuffer (); } Resolució currentResolution = Screen.currentResolution; // Textura Y if (_videoTextureY == null) {_videoTextureY = Texture2D. CreateExternalTexture (currentResolution.width, currentResolution.height, TextureFormat. R8, false, false, (System. IntPtr) handles.textureY); _videoTextureY.filterMode = FiltreMode. Bilineal; _videoTextureY.wrapMode = TextureWrapMode. Repetiu; m_ClearMaterial. SetTexture ("_ textureY", _videoTextureY); } // Textura CbCr si (_videoTextureCbCr == null) {_videoTextureCbCr = Texture2D. CreateExternalTexture (currentResolution.width, currentResolution.height, TextureFormat. RG16, false, false, (System. IntPtr) handles.textureCb) _videoTextureCbCr.filterMode = FiltreMode. Bilineal; _videoTextureCbCr.wrapMode = TextureWrapMode. Repetiu; 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 () {if (! bCommandBufferInitialized) {InitializeCommandBuffer (); } m_ClearMaterial. SetTexture ("_ textureY", _videoTextureY); m_ClearMaterial. SetTexture ("_ textureCbCr", _videoTextureCbCr); m_ClearMaterial. SetMatrix ("_ DisplayTransform", _displayTransform); } #endif}}

Pas 9: gairebé acabat

Quasi fet!
Quasi fet!

Finalment, quan fem clic a la pantalla i col·loquem el portal, volem que sempre ens doni la cara. Per fer-ho, aneu a l'script "UnityARHitTestExample" del portal. Substitueix tot el que hi ha a dins:

utilitzant el sistema;

utilitzant System. Collections. Generic; espai de noms UnityEngine. XR.iOS {classe pública UnityARHitTestExample: MonoBehaviour {public Transform m_HitTransform; flotador públic maxRayDistance = 30,0f; public LayerMask collisionLayer = 1 <0) {foreach (var hitResult in hitResults) {Debug. Log ("He aconseguit!"); 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 = nou Vector3 (currAngle.x, transform.eulerAngles.y, currAngle.z); tornar cert; }} retornar fals; } // Actualització es diu una vegada per cada frame void Actualització () {#if UNITY_EDITOR // només utilitzarem aquest script al costat de l'editor, tot i que no hi ha res que impedeixi que funcioni al dispositiu si (Input. GetMouseButtonDown (0)) {Ray ray = Camera.main. ScreenPointToRay (Input.mousePosition); Èxit de RaycastHit; // intentarem colpejar un dels objectes del joc de col·lisionament d'avions generats pel complement // efectivament similar a la crida a HitTest amb ARHitTestResultType. ARHitTestResultTypeExistingPlaneUsingExtent if (Physics. Raycast (ray, out hit, maxRayDistance, collisionLayer)) {// aconseguirem la posició des del punt de contacte 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)); // i la rotació a partir de la transformació del col·lisionador pla 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); Punt ARPoint = ARPoint nou {x = screenPosition.x, y = screenPosition.y}; // prioritzar tipus reults ARHitTestResultType = {resultTypes ARHitTestResultType. ARHitTestResultTypeExistingPlaneUsingExtent, // si voleu utilitzar usen plànols infinits això: //ARHitTestResultType. ARHitTestResultTypeExistingPlane, ARHitTestResultType. ARHitTestResultTypeHorizontalPlane, ARHitTestResultType. ARHitTestResultTypeFeaturePoint}; foreach (ARHitTestResultType resultType a resultTypes) {if (HitTestWithResultType (punt, resultType)) {return; }}}} #endif}}}

Pas 10: poseu l'aplicació al telèfon

Poseu l'aplicació al vostre telèfon
Poseu l'aplicació al vostre telèfon

Finalment ja hem acabat. Aneu al fitxer, configureu la configuració i feu clic a Compila. Obriu Xcode i trieu la carpeta que es va crear a partir de la compilació. Trieu el vostre equip de desenvolupament i poseu l'aplicació al telèfon. És possible que vulgueu canviar els colors de les partícules i el skybox per adaptar-les a les vostres necessitats. Avisa’m als comentaris si tens cap pregunta i gràcies per buscar-la.

Recomanat: