AR portal naopako od čudnih stvari: 10 koraka (sa slikama)
AR portal naopako od čudnih stvari: 10 koraka (sa slikama)

Video: AR portal naopako od čudnih stvari: 10 koraka (sa slikama)

Video: AR portal naopako od čudnih stvari: 10 koraka (sa slikama)
Video: Моя работа наблюдать за лесом и здесь происходит что-то странное 2025, Januar
Anonim
AR portal naopako od čudnih stvari
AR portal naopako od čudnih stvari
AR portal naopako od čudnih stvari
AR portal naopako od čudnih stvari

Ovaj Instructable će proći kroz stvaranje mobilne aplikacije za iPhone s proširenom stvarnošću s portalom koji vodi naopako od Stranger Things. Možete ući u portal, prošetati i izaći. Sve unutar portala može se vidjeti samo kroz portal dok ne uđete unutra. Kad jednom uđete, sve će se okretati posvuda, sve dok se ne vratite u stvarni svijet. Koristit ćemo Unity 3D engine za video igre s Apple ARKit dodatkom. Sav softver koji ćemo koristiti može se besplatno preuzeti i koristiti. Ne morate biti stručnjak da biste to pratili, proći ćemo svaki korak!

Korak 1: Pokrenite novi projekat Unity

Pokrenite novi projekat Unity
Pokrenite novi projekat Unity

Prvo preuzmite Unity3D i svakako instalirajte datoteke za izgradnju za IOS platformu. Također ćete morati preuzeti Xcode i prijaviti se za besplatni Apple developer račun. Vaš iPhone će također morati imati IOS 11 ili noviji. Od 5. februara 2018. IOS 11.3 je izašao, ali xCode 9.2 još nema datoteke podrške za njega. Stoga, ako koristite najnoviju verziju IOS -a, preuzmite najnoviju beta verziju Xcode sa Apple. Developer.com.

Nakon što imate sve potrebne programe, otvorite Unity i pokrenite novi projekt, nazovite ga kako želite. Trebat će nam dodatak Apple ARKit kako bismo mogli koristiti kameru našeg telefona za otkrivanje tla i postavljanje objekata na pod. Uvezimo to sada tako što ćemo otići na karticu Asset Store i pretražiti "ARKit". Morat ćete stvoriti besplatni Unity račun ako ga već nemate, a zatim kliknite uvoz da biste dobili dodatak.

Idite do mape primjera u mapi ARKit i pronađite "UnityARKitScene". Dvaput kliknite na nju da biste je otvorili. Ovu scenu ćemo koristiti kao polaznu tačku i graditi odavde. Ova scena će vam prema zadanim postavkama omogućiti otkrivanje tla, a kada dodirnete ekran, kocka će biti postavljena u taj položaj.

Dopustimo prvo da izravnamo postavke izgradnje kako ne bismo zaboravili to učiniti kasnije. Kliknite na datoteku, izradite postavke i uklonite sve scene s tog popisa. Kliknite Dodaj otvorene scene da biste dodali našu trenutnu. Posljednje što ovdje moramo postaviti je da postavke igrača idu do identifikatora paketa, a format za ovaj niz je com. YourCompanyName. YourAppName, pa u mom slučaju radim nešto poput com. MatthewHallberg. PortalTest.

Korak 2: Postavite scenu

Postavite scenu
Postavite scenu

Prvo pogledajte lijevo i pronađite objekt igre pod nazivom "GeneratePlanes". Kada je to istaknuto, pogledajte desno sada i kliknite potvrdni okvir da biste ga onemogućili. Na ovaj način nemamo generirane ružne plave kvadrate kada ARKit detektira ravninu tla. Zatim izbrišite objekt igre "RandomCube" jer to ne želimo vidjeti u našoj sceni.

Sada moramo prvo stvoriti vrata našeg portala. Izbrišite kocku koja je podređena od "HitCubeParent". Desnom tipkom miša kliknite i odaberite stvoriti prazan objekt igre. Preimenujte ga u "Portal". Sada desnom tipkom miša kliknite na taj objekt i stvorite kocku, to će je učiniti podređenom portala. Preimenujte ga u "PostLeft" i ovo će biti lijevi post našeg portala. Smanjite ga tako da je x 1, y je 28, a z jedno. Uradite isto za pravi post. Sada kreirajte gornji stup i skalirajte y na 14. Okrenite ovo bočno i pomaknite ga tako da povezuje ostale stupove. Učinite cijelu skalu portala 1,3 x 1,4 x 1.

Idite na google i upišite teksturu drveta ili kore. Preuzmite jednu od tih slika i prevucite je u fasciklu sa sredstvima u programu Unity. Sada povucite tu sliku na sve svoje postove na portalu.

Ponovo kliknite objekt "Portal" i kliknite Dodaj komponentu s desne strane. Dodajte mu skriptu "UnityARHitTestExample". Tamo postoji prazan utor za "Hit Transform", povucite objekt "HitCubeParent" u taj utor.

Korak 3: Napravimo neke čestice

Napravimo neke čestice
Napravimo neke čestice

Sada ćemo koristiti sistem Unity Particle za stvaranje efekta dima i plutajućih čestica za naš portal. Idite na Sredstva na gornjoj traci menija, Standardna sredstva i uvezite sisteme čestica.

Napravite dva prazna objekta igre na svom portalu i jedan nazovite "SmokeParticles", a drugi "FloatingParticles".

Česticama dima dodajte komponentu sistema čestica.

Ova komponenta ima hrpu opcija, ali samo moramo promijeniti nekoliko.

Promijenite početnu boju u nešto tamno plavo sa oko 50% prozirnosti. Učinite emisiju 100. Unutar oblika, napravite radijus.01. U dijelu za prikaz na dnu promijenite minimalnu veličinu na.8 i maksimalnu veličinu na 5. Na komponenti materijala samo odaberite dimni materijal s popisa, ali to ćemo promijeniti kasnije.

Sada dodajte sistem čestica objektu igre s plutajućim česticama i postavite emisiju na 500. Podesite životni vijek početka na 2, polumjer na 10, minimalnu veličinu čestica na.01, a najveću veličinu čestica na.015. Za sada postavite materijal na zadane čestice.

Na kraju uzmite oba predmeta igre i okrenite ih za 90 stupnjeva na x i podignite ih u zrak tako da emitiraju prema dolje na portalu.

Korak 4: Usporavanje čestica

Usporavanje čestica
Usporavanje čestica

Budući da želimo da ove čestice pokrivaju veliko područje, ali i da se sporo kreću, moramo stvoriti vlastitu funkciju uzorka. Zato desnom tipkom miša kliknite u folderu imovine i stvorite novu C# skriptu i nazovite je "ParticleSample". Kopirajte i zalijepite ovaj kod:

pomoću System. Collections;

pomoću System. Collections. Generic; koristeći UnityEngine; javna klasa ParticleSample: MonoBehaviour {private ParticleSystem ps; // Koristi ovo za inicijalizaciju void Start () {ps = GetComponent (); StartCoroutine (SampleParticleRoutine ()); } IEnumerator SampleParticleRoutine () {var main = ps.main; main.simulationSpeed = 1000f; ps. Play (); yield return new WaitForSeconds (.1f); main.simulationSpeed =.05f; }}

Sada povucite ovu skriptu na svaki od vaših objekata igre sistema čestica.

Korak 5: Kreiranje portala

Kreiranje portala!
Kreiranje portala!

Sada moramo stvoriti portal pa desnom tipkom miša kliknite objekt igre na portalu i stvorite četverokut. Smanjite quad tako da pokrije cijeli portal, ovo će postati naš prozor portala. Prvo što mu moramo dodati je portalni shader, koji će prikazati samo objekte sa drugim određenim shader -om. Desnom tipkom miša kliknite u folderu resursa i stvorite novi neosvijetljeni zasjenjivač. Uklonite sve unutra i zalijepite ovaj kod:

Shader "Portal/portalWindow"

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

Desnom tipkom miša kliknite hijerarhiju i stvorite novi materijal, nazovite ga PortalWindowMat, u padajućem izborniku za ovaj materijal pronađite odjeljak portala i odaberite prozor portala. Povucite ovaj materijal na četvorku portala.

Korak 6: Uređivači čestica

Shader Shaders
Shader Shaders

Ponovo desnom tipkom miša kliknite u folderu resursa i stvorite novi shader. Moramo napraviti sjenila za čestice koje ulaze u portal. Zamijenite sav kôd ovim:

Shader "Portal/čestice" {

Svojstva {_TintColor ("Boja nijanse", Boja) = (0,5, 0,5, 0,5, 0,5) _MainTex ("Tekstura čestica", 2D) = "bijela" {} _InvFade ("Faktor mekih čestica", Raspon (0,01, 3,0)) = 1.0 _Stencil ("stencil", int) = 6} Kategorija {Tags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" "PreviewType" = "Plane"} Blend SrcAlpha OneMinusSrcAlpha ColorMask RGB isključenje Osvjetljenje Isključeno ZWrite Isključeno SubShader {šablon {Ref 1 Comp [_Stencil]} Proslijedi {CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 2.0 #pragma multi_compile_particles #pragma multi_compile_fog #include "UnityCGe fixed4 _TintColor; struct appdata_t {float4 vertex: POSITION; fiksno4 boja: COLOR; float2 texcoord: TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID}; struct v2f {float4 vertex: SV_POSITION; fiksno4 boja: COLOR; float2 texcoord: TEXCOORD0; UNITY_FOG_COORDS (1) #ifdef SOFTPARTICLES_ON float4 projPos: TEXCOORD2; #endif UNITY_VERTEX_OUTPUT_STEREO}; float4 _MainTex_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); return o; } UNITY_DECLARE_DEPTH_TEXTURE (_CameraDepthTexture); float _InvFade; fixed4 frag (v2f i): SV_Target {#ifdef SOFTPARTICLES_ON float scenaZ = 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 *= fade; #endif fixed4 col = 2.0f * i.color * tex2D (_MainTex, i.texcoord); UNITY_APPLY_FOG (i.fogCoord, col); return col; } ENDCG}}}}

Napravite dva nova materijala, jedan pod nazivom portalSmoke, i jedan pod nazivom portalParticles.

Za svakoga odaberite ovaj shader, s padajućeg izbornika, na portalima, čestice. Za čestice dima odaberite teksturu dima, a za čestice teksturu čestica. Promijenite boju dima u tamnije plavu sa oko 50% prozirnosti. Idite na renderer komponentu svakog sistema čestica na svom portalu i odaberite odgovarajuće materijale koje smo upravo stvorili.

Korak 7: Kreirajte Skybox

Kreirajte Skybox
Kreirajte Skybox

Sada, da bismo zaista stvorili izgled naopačke, moramo sve tonirati tamno plavo. Za ovo ćemo koristiti prozirni skybox pa napravite novi shader i zalijepite ovaj kod:

Shader "Portal/portalSkybox" {

Svojstva {_Tint ("Boja nijanse", Boja) = (.5,.5,.5,.5) [Gama] _Ekspozicija ("Ekspozicija", Opseg (0, 8)) = 1.0 _Rotation ("Rotacija", Raspon (0, 360)) = 0 [NoScaleOffset] _Tex ("Cubemap (HDR)", Cube) = "grey" {} _Stencil ("StencilNum", int) = 6} Podsenzor {Oznake {"Queue" = "Pozadina" "RenderType" = "Pozadina" "PreviewType" = "Skybox"} Izdvoji ZWrite Off Blend SrcAlpha OneMinusSrcAlpha šablon {Ref 1 Comp [_Stencil]} Prođi {CGPROGRAM #pragma vertex ver #pragma fragment fragment #pragma target 2.0 #CGclude ".cginc "samplerCUBE _Tex; half4 _Tex_HDR; half4 _Tint; pola _izlaganje; float _Rotation; float3 RotateAroundYInDegrees (float3 vertex, float stepeni) {float alpha = stepeni * UNITY_PI / 180.0; plovak 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 (rotirano); 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 *= _Izlaganje; return half4 (c,.5); } ENDCG}} Rezervno isključeno}

Sada kreirajte novi skybox materijal, nazovite ga "PortalSkybox" i odaberite ovaj portalSkybox shader iz izbornika portala. Idite na Window, Lighting na vrhu i odaberite ovaj skybox koji smo upravo stvorili. Idite do glavne kamere i postavite jasne zastavice u skybox. Dok smo ovdje, dodajmo neke komponente na našu kameru kako bismo mogli otkriti sudare. Dodajte kameri komponentu s čvrstim tijelom i poništite odabir upotrebe gravitacije. Dodajte okvirni sudarač i provjerite je li okidač. Postavite okvirne sudarače veličine.5 x 1 x 4. Postavite ravninu izrezivanja na kameri na.01.

Korak 8: Logika portala

Logika portala
Logika portala

Posljednje što trebamo učiniti je stvoriti logiku koja kontrolira naš portal. Kreirajte novu C# skriptu i nazovite je PortalController.

pomoću System. Collections;

pomoću System. Collections. Generic; koristeći UnityEngine; imenski prostor UnityEngine. XR.iOS {javni razred PortalController: MonoBehaviour {javni materijal materijali; javni MeshRenderer meshRenderer; javni UnityARVideo UnityARVideo; privatni bool isInside = false; privatni bool isOutside = true; // Koristi ovo za inicijalizaciju 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; yield return new WaitForEndOfFrame (); meshRenderer.enabled = false; foreach (Materijal mat u materijalima) {mat. SetInt ("_Stencil", stencilNum); } yield return new WaitForEndOfFrame (); meshRenderer.enabled = true; UnityARVideo.shouldRender = true; }}}

Prevucite ovu novu skriptu u prozor vašeg portala. Ovo će nas prevesti unutra i van portala kad god se sudarač na našoj kameri sudari s prozorom portala. Sada u funkciji koja mijenja sve materijale kažemo dodatku ARkit da ne iscrtava okvir, pa idite na glavnu kameru i otvorite UnityARVideo skriptu. Kreirajte javni bool shouldRender na vrhu i postavite ga jednakim true. Dolje u funkciji OnPreRender () umotajte sve u if naredbu gdje će se sve izvoditi samo ako shouldRender je istina. Cijela skripta bi trebala izgledati ovako:

pomoću System;

pomoću System. Runtime. InteropServices; koristeći UnityEngine; koristeći UnityEngine. Rendering; imenski prostor UnityEngine. XR.iOS {javna klasa UnityARVideo: MonoBehaviour {javni materijal m_ClearMaterial; [HideInInspector] javni bool shouldRender = true; privatni CommandBuffer m_VideoCommandBuffer; privatno Texture2D _videoTextureY; privatno Texture2D _videoTextureCbCr; privatni Matrix4x4 _displayTransform; privatni 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 = novi 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; } #i! UNITY_EDITOR javna void OnPreRender () {if (shouldRender) {ARTextureHandles handles = UnityARSessionNativeInterface. GetARSessionNativeInterface (). GetARVideoTextureHandles (); if (handles.textureY == System. IntPtr. Zero || handles.textureCbCr == System. IntPtr. Zero) {return; } if (! bCommandBufferInitialized) {InitializeCommandBuffer (); } Rezolucija currentResolution = Screen.currentResolution; // Tekstura Y ako (_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); } // Tekstura CbCr ako (_videoTextureCbCr == null) {_videoTextureCbCr = Texture2D. CreateExternalTexture (currentResolution.width, currentResolution.height, TextureFormat. RG16, false, false, (System. IntPtr); _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; } javna praznina 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}}

Korak 9: Skoro gotovo

Skoro gotovo!
Skoro gotovo!

Konačno, kada kliknemo na ekran i postavimo portal, želimo da nam uvijek bude okrenut. Da biste to učinili, idite na skriptu "UnityARHitTestExample" na portalu. Zamijenite sve unutra sa ovim:

pomoću System;

pomoću System. Collections. Generic; imenski prostor UnityEngine. XR.iOS {javna klasa UnityARHitTestExample: MonoBehaviour {public Transform m_HitTransform; javni plovak maxRayDistance = 30.0f; javni LayerMask collisionLayer = 1 <0) {foreach (var hitResult u hitResults) {Debug. Log ("Got hit!"); 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 = novi Vector3 (currAngle.x, transform.eulerAngles.y, currAngle.z); return true; }} return false; } // Ažuriranje se poziva jednom po okviru void Update () {#if UNITY_EDITOR // ovu skriptu ćemo koristiti samo na strani uređivača, iako ne postoji ništa što bi je spriječilo da radi na uređaju ako (Input. GetMouseButtonDown (0)) {Ray ray = Camera.main. ScreenPointToRay (Input.mousePosition); RaycastHit hit; // pokušat ćemo pogoditi jedan od objekata avionskih sudarača koje je generirao dodatak // efektivno slično pozivanju HitTesta s ARHitTestResultType. ARHitTestResultTypeExistingPlaneUsingExtent if (Physics. Raycast (ray, out hit, maxRayDistance, collisionLayer)) {// poziciju ćemo dobiti iz kontaktne tačke 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 rotacija iz transformacije ravnog sudarača 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 točka = nova ARPoint {x = screenPosition.x, y = screenPosition.y}; // Dati prioritet reults vrste ARHitTestResultType resultTypes = {ARHitTestResultType. ARHitTestResultTypeExistingPlaneUsingExtent, // ako želite da koristite beskonačnu avione koristiti ovo: //ARHitTestResultType. ARHitTestResultTypeExistingPlane, ARHitTestResultType. ARHitTestResultTypeHorizontalPlane, ARHitTestResultType. ARHitTestResultTypeFeaturePoint}; foreach (ARHitTestResultType resultType u resultTypes) {if (HitTestWithResultType (point, resultType)) {return; }}}} #endif}}}

Korak 10: Postavite aplikaciju na telefon

Stavite aplikaciju na telefon!
Stavite aplikaciju na telefon!

Konačno smo završili. Idite u datoteku, postavite postavke i kliknite na izgradnju. Otvorite Xcode i odaberite mapu koja je stvorena iz verzije. Odaberite svoj razvojni tim i stavite aplikaciju na telefon! Možda ćete htjeti promijeniti boje čestica i skybox -a kako bi odgovarali vašim potrebama. Javite mi u komentarima ako imate pitanja i hvala što ste pogledali!