Sommario:

Portale AR per il sottosopra di Stranger Things: 10 passaggi (con immagini)
Portale AR per il sottosopra di Stranger Things: 10 passaggi (con immagini)

Video: Portale AR per il sottosopra di Stranger Things: 10 passaggi (con immagini)

Video: Portale AR per il sottosopra di Stranger Things: 10 passaggi (con immagini)
Video: Il RIASSUNTONE di STRANGER THINGS 4 in 30 minuti #ilridoppiatore 2024, Novembre
Anonim
Portale AR per il sottosopra di Stranger Things
Portale AR per il sottosopra di Stranger Things
Portale AR per il sottosopra di Stranger Things
Portale AR per il sottosopra di Stranger Things

Questo Instructable passerà attraverso la creazione di un'app mobile in realtà aumentata per iPhone con un portale che conduce al capovolto da Stranger Things. Puoi entrare nel portale, camminare e tornare fuori. Tutto all'interno del portale può essere visto solo attraverso il portale finché non si entra. Una volta dentro, tutto verrà visualizzato ovunque, finché non tornerai nel mondo reale. Utilizzeremo il motore di videogiochi Unity 3D con il plug-in Apple ARKit. Tutto il software che utilizzeremo può essere scaricato e utilizzato gratuitamente. Non è necessario essere un esperto per seguire, noi seguiremo ogni passaggio!

Passaggio 1: avviare un nuovo progetto Unity

Inizia un nuovo progetto di unità
Inizia un nuovo progetto di unità

Prima di tutto, scarica Unity3D e assicurati di installare i file di build per la piattaforma IOS. Dovrai anche scaricare Xcode e registrarti per un account sviluppatore Apple gratuito. Il tuo iPhone dovrà anche eseguire IOS 11 o versioni successive. A partire da oggi 5 febbraio 2018, IOS 11.3 è uscito ma xCode 9.2 non ha ancora file di supporto per esso. Quindi, se stai utilizzando l'ultima versione di IOS, assicurati di scaricare l'ultima versione beta di Xcode da Apple. Developer.com.

Una volta che hai tutti i programmi necessari, apri Unity e avvia un nuovo progetto, chiamalo come vuoi. Avremo bisogno del plug-in Apple ARKit in modo da poter utilizzare la fotocamera del nostro telefono per rilevare il terreno e posizionare oggetti sul pavimento. Importiamolo ora andando nella scheda Asset Store e cercando "ARKit". Dovrai creare un account Unity gratuito se non ne hai già uno, quindi fai clic su importa per ottenere il plug-in.

Passare alla cartella degli esempi nella cartella ARKit e trovare "UnityARKitScene". Fare doppio clic per aprirlo. Useremo questa scena come punto di partenza e partiremo da qui. Questa scena per impostazione predefinita ti consentirà di rilevare il terreno e quando tocchi lo schermo, un cubo verrà posizionato in quella posizione.

Per prima cosa mettiamo a posto le nostre impostazioni di costruzione in modo da non dimenticarci di farlo in seguito. Fai clic su file, crea impostazioni e rimuovi tutte le scene da quell'elenco. Fare clic su aggiungi scene aperte per aggiungere quella attuale. L'ultima cosa che dobbiamo impostare qui è che nelle impostazioni del lettore scendi all'identificatore del bundle e il formato per questa stringa è com. YourCompanyName. YourAppName, quindi nel mio caso faccio qualcosa come com. MatthewHallberg. PortalTest.

Passaggio 2: imposta la scena

Imposta la scena
Imposta la scena

Per prima cosa dai un'occhiata a sinistra e trova l'oggetto di gioco chiamato "GeneratePlanes". Con quello evidenziato, guarda ora a destra e fai clic sulla casella di controllo per disabilitarlo. In questo modo non abbiamo i brutti quadrati blu generati quando ARKit rileva un piano di terra. Quindi elimina l'oggetto di gioco "RandomCube" perché non vogliamo vederlo nella nostra scena.

Ora dobbiamo prima creare la nostra porta del portale. Elimina il cubo figlio di "HitCubeParent". Fare clic con il tasto destro e scegliere Crea oggetto di gioco vuoto. Rinominalo "Portale". Ora fai clic con il pulsante destro del mouse su quell'oggetto e crea un cubo, questo lo renderà figlio del portale. Rinominalo "PostLeft" e questo sarà il post di sinistra del nostro portale. Scalalo in modo che x sia 1, y sia 28 e z sia uno. Fai la stessa cosa per il post giusto. Ora crea il palo in alto e scala la y a 14. Giralo di lato e spostalo in modo che colleghi gli altri post. Rendi l'intero portale in scala 1,3 x 1,4 x 1.

Vai su google e digita la trama del legno o della corteccia. Scarica una di quelle immagini e trascinala nella cartella delle risorse in Unity. Ora trascina quell'immagine su tutti i post del tuo portale.

Fare nuovamente clic sull'oggetto "Portale" e fare clic su Aggiungi componente a destra. Aggiungi lo script "UnityARHitTestExample" ad esso. C'è uno slot vuoto lì per "Hit Transform", trascina l'oggetto "HitCubeParent" in quello slot.

Passaggio 3: facciamo alcune particelle

Facciamo alcune particelle
Facciamo alcune particelle

Ora useremo il sistema Unity Particle per creare un effetto fumo e particelle fluttuanti all'interno del nostro portale. Vai a Risorse nella barra dei menu in alto, risorse standard e importa i sistemi di particelle.

Crea due oggetti di gioco vuoti all'interno del tuo portale e chiama uno "SmokeParticles" e l'altro "FloatingParticles".

Aggiungi un componente del sistema particellare alle particelle di fumo.

Questo componente ha un sacco di opzioni, ma abbiamo solo bisogno di cambiarne un paio.

Cambia il colore iniziale in qualcosa di blu scuro con circa il 50% di trasparenza. Rendi il tasso di emissione 100. All'interno della forma, crea il raggio.01. Nella parte del renderer in basso cambia la dimensione minima in.8 e la dimensione massima in 5. Sul componente materiale scegli semplicemente il materiale del fumo dall'elenco, ma lo cambieremo in seguito.

Aggiungi ora un sistema di particelle all'oggetto del gioco di particelle fluttuanti e imposta l'emissione su 500. Imposta la durata iniziale su 2, il raggio su 10, la dimensione minima delle particelle su.01 e la dimensione massima delle particelle su.015. Imposta il materiale sulla particella predefinita per ora.

Infine prendi entrambi gli oggetti di gioco e ruotali di 90 gradi sulla x e sollevali in aria in modo che emettano verso il basso sulla porta del portale.

Passaggio 4: rallentamento delle particelle

Rallentare le particelle
Rallentare le particelle

Poiché vogliamo che queste particelle coprano una vasta area ma si muovano anche lentamente, dobbiamo creare la nostra funzione di campionamento. Quindi fai clic con il pulsante destro del mouse nella cartella delle risorse e crea un nuovo script C# e chiamalo "ParticleSample". Copia e incolla questo codice:

utilizzando System. Collections;

utilizzando System. Collections. Generic; utilizzando UnityEngine; public class ParticleSample: MonoBehaviour { private ParticleSystem ps; // Usalo per l'inizializzazione void Start() { ps = GetComponent (); StartCoroutine (SampleParticleRoutine()); } IEnumerator SampleParticleRoutine(){ var main = ps.main; main.simulationSpeed = 1000f; ps. Riproduci (); yield return new WaitForSeconds (.1f); main.simulationSpeed =.05f; } }

Ora trascina questo script su ciascuno dei tuoi oggetti di gioco del sistema particellare.

Passaggio 5: creazione del portale

Creazione del portale!
Creazione del portale!

Ora dobbiamo creare il portale, quindi fai clic con il pulsante destro del mouse sull'oggetto di gioco del portale e crea un quad. Scala il quad in modo che copra l'intero portale, questa diventerà la nostra finestra del portale. La prima cosa che dobbiamo aggiungere è lo shader del portale, questo renderà solo gli oggetti con un altro shader specifico su di essi. Fare clic con il tasto destro nella cartella delle risorse e creare un nuovo shader spento. Rimuovi tutto e incolla questo codice:

Shader "Portale/Finestra del portale"

{ SubShader { Zwrite off Colormask 0 elimina Stencil { Ref 1 Passa sostituzione } Passa { } } }

Fai clic con il pulsante destro del mouse nella gerarchia e crea un nuovo materiale, chiamalo PortalWindowMat, nel menu a discesa per questo materiale trova la sezione del portale e scegli la finestra del portale. Trascina questo materiale sul quad del portale.

Passaggio 6: ombreggiatori di particelle

Shader di particelle
Shader di particelle

Fare nuovamente clic con il pulsante destro del mouse nella cartella delle risorse e creare un nuovo shader. Dobbiamo creare gli shader per le particelle che entrano nel portale. Sostituisci tutto il codice con questo:

Shader "Portale/Particelle" {

Proprietà { _TintColor ("Colore tinta", Colore) = (0,5, 0,5, 0,5, 0,5) _MainTex ("Consistenza delle particelle", 2D) = "bianco" {} _InvFade ("Fattore di particelle morbide", Intervallo (0,01, 3,0)) = 1.0 _Stencil("stencil", int) = 6 } Categoria { Tag { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" } Blend SrcAlpha OneMinusSrcAlpha ColorMask RGB Cull Off Illuminazione Off ZWrite Off SubShader { Stencil{ Ref 1 Comp[_Stencil] } Passa { CGPROGRAM #pragma vertice vert #pragma frammento frag #pragma target 2.0 #pragma multi_compile_particles #pragma multi_compile_fog #include "UnityCG.cginc" sampler2;D _Ma fix4 _TintColor; struct appdata_t { float4 vertice: POSIZIONE; fixed4 colore: COLORE; float2 texcoord: TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2f { float4 vertice: SV_POSITION; fixed4 colore: COLORE; 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.vertice); ritorno o; } UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); float _InvFade; fix4 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 *= dissolvenza; #endif fixed4 col = 2.0f * i.color * tex2D(_MainTex, i.texcoord); UNITY_APPLY_FOG(i.fogCoord, col); ritorno col; } ENDCG } } } }

Crea due nuovi materiali, uno chiamato portalSmoke e uno chiamato portalParticles.

Per ognuno scegli questo shader, dal menu a tendina, in portali, particelle. Per le particelle di fumo scegli una trama di fumo e per le particelle scegli la trama di particelle. Cambia il colore del fumo in un blu più scuro con circa il 50% di trasparenza. Vai al componente renderer di ciascun sistema di particelle nel tuo portale e scegli i rispettivi materiali che abbiamo appena creato.

Passaggio 7: creare lo Skybox

Crea lo Skybox
Crea lo Skybox

Ora per creare davvero il tipo di look capovolto dobbiamo tingere tutto di blu scuro. Per questo useremo uno skybox trasparente, quindi crea un nuovo shader e incolla questo codice:

Shader "Portale/portaleSkybox" {

Proprietà { _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) = "grey" {} _Stencil("StencilNum", int) = 6 } SubShader { Tags { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" } Elimina ZWrite Off Blend SrcAlpha OneMinusSrcAlpha Stencil{ Ref 1 Comp[_Stencil] } Passa { CGPROGRAM #pragma vertex vert #pragma frammenti frag #pragma target 2.0 #include "UnityCG.cginc" samplerCUBE _Tex; half4 _Tex_HDR; half4 _Tinta; metà _Esposizione; float _Rotation; float3 RotateAroundYInDegrees (float3 vertice, float gradi) { float alpha = gradi * UNITY_PI / 180.0; galleggiante sina, cosa; sincos(alpha, sina, cosa); float2x2 m = float2x2(cosa, -sina, sina, cosa); return float3(mul(m, vertice.xz), vertice.y).xzy; } struct appdata_t { float4 vertice: POSIZIONE; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2f { float4 vertice: 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 rotante = RotateAroundYInDegrees(v.vertex, _Rotation); o.vertex = UnityObjectToClipPos(ruotato); o.texcoord = v.vertice.xyz; ritorno 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 *= _Esposizione; restituire metà4(c,.5); } ENDCG } } Fallback Off }

Ora crea un nuovo materiale skybox, chiamalo "PortalSkybox" e scegli questo shader portalSkybox dal menu del portale. Vai su Finestra, Illuminazione, in alto e scegli questo skybox che abbiamo appena creato. Vai alla fotocamera principale e imposta i flag di cancellazione sullo skybox. Mentre siamo qui, aggiungiamo alcuni componenti sulla nostra fotocamera in modo da poter rilevare le collisioni. Aggiungi un componente rigido alla videocamera e deseleziona Usa gravità. Aggiungi un collisore di scatole e seleziona il trigger. Rendi i collisori della scatola di dimensioni 0,5 x 1 x 4. Imposta il piano di ritaglio sulla fotocamera su 0,01.

Passaggio 8: logica del portale

Logica del portale
Logica del portale

L'ultima cosa che dobbiamo fare è creare la logica che controlla il nostro portale. Crea un nuovo script C# e chiamalo PortalController.

utilizzando System. Collections;

utilizzando System. Collections. Generic; utilizzando UnityEngine; namespace UnityEngine. XR.iOS{ public class PortalController: MonoBehaviour { public Materialmaterials; public MeshRenderer meshRenderer; pubblico UnityARVideo UnityARVideo; bool privato isInside = false; bool privato isOutside = true; // Usalo per l'inizializzazione 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 = vero; Portale interno (); } } else { if (isInside) { isInside = false; isOutside = vero; Portale esterno (); } } } 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 (Materiale nei materiali) { mat. SetInt ("_Stencil", stencilNum); } yield return new WaitForEndOfFrame (); meshRenderer.enabled = vero; UnityARVideo.shouldRender = true; } } }

Trascina questo nuovo script nella finestra del tuo portale. Questo ci farà entrare e uscire dal portale ogni volta che il collisore sulla nostra telecamera entra in collisione con la finestra del portale. Ora nella funzione che cambia tutti i materiali diciamo al plugin ARkit di non renderizzare il fotogramma, quindi vai alla fotocamera principale e apri lo script UnityARVideo. Crea un bool pubblico shouldRender in alto e impostalo uguale a true. Giù nella funzione OnPreRender() avvolge tutto in un'istruzione if in cui tutto all'interno verrà eseguito solo se shouldRender è vero. L'intero script dovrebbe assomigliare a questo:

utilizzando il sistema;

utilizzando System. Runtime. InteropServices; utilizzando UnityEngine; utilizzando UnityEngine. Rendering; namespace UnityEngine. XR.iOS { public class UnityARVideo: MonoBehaviour { public Material m_ClearMaterial; [HideInInspector] public bool shouldRender = true; CommandBuffer privato m_VideoCommandBuffer; privato Texture2D _videoTextureY; privato Texture2D _videoTextureCbCr; privato Matrix4x4 _displayTransform; bool privato 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 InizializzaCommandBuffer() { m_VideoCommandBuffer = new 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 handle = UnityARSessionNativeInterface. GetARSessionNativeInterface (). GetARVideoTextureHandles(); if (handles.textureY == System. IntPtr. Zero || handle.textureCbCr == System. IntPtr. Zero) { return; } if (!bCommandBufferInitialized) { InitializeCommandBuffer (); } Risoluzione currentResolution = Screen.currentResolution; // Texture 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); } // Texture 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() { if (!bCommandBufferInitialized) { InitializeCommandBuffer (); } m_ClearMaterial. SetTexture("_textureY", _videoTextureY); m_ClearMaterial. SetTexture("_textureCbCr", _videoTextureCbCr); m_ClearMaterial. SetMatrix("_DisplayTransform", _displayTransform); } #finisci se } }

Passaggio 9: quasi fatto

Quasi fatto!
Quasi fatto!

Infine, quando facciamo clic sullo schermo e posizioniamo il portale, vogliamo che sia sempre rivolto verso di noi. Per fare ciò vai allo script "UnityARHitTestExample" sul portale. Sostituisci tutto all'interno con questo:

utilizzando il sistema;

utilizzando System. Collections. Generic; namespace UnityEngine. XR.iOS { public class UnityARHitTestExample: MonoBehaviour { public Transform m_HitTransform; public float maxRayDistance = 30.0f; public LayerMask collisionLayer = 1 < 0) { foreach (var hitResult in hitResults) { Debug. Log ("Ho colpito!"); 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 = new Vector3 (currAngle.x, transform.eulerAngles.y, currAngle.z); restituire vero; } } restituisce falso; } // Update viene chiamato una volta per frame void Update () { #if UNITY_EDITOR // useremo questo script solo dal lato dell'editor, anche se non c'è nulla che possa impedirgli di funzionare sul dispositivo if (Input. GetMouseButtonDown (0)) { Ray ray = Camera.main. ScreenPointToRay (Input.mousePosition); Colpo di RaycastHit; // proveremo a colpire uno degli oggetti di gioco del collisore aereo che sono stati generati dal plugin // in modo simile alla chiamata di HitTest con ARHitTestResultType. ARHitTestResultTypeExistingPlaneUsingExtent if (Physics. Raycast (ray, out hit, maxRayDistance, collisionLayer)) { // otterremo la posizione dal punto di contatto 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)); //e la rotazione dalla trasformazione del collisore aereo 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 punto = nuovo ARPoint { x = screenPosition.x, y = screenPosition.y }; // dare priorità ai tipi di risultati ARHitTestResultType resultTypes = { ARHitTestResultType. ARHitTestResultTypeExistingPlaneUsingExtent, // se si desidera utilizzare piani infiniti, utilizzare questo: //ARHitTestResultType. ARHitTestResultTypeExistingPlane,ARHult. TRult. foreach (ARHitTestResultType resultType in resultTypes) { if (HitTestWithResultType (punto, risultatoTipo)) { return; } } } } #finisci se } } }

Passaggio 10: installa l'app sul tuo telefono

Metti l'app sul tuo telefono!
Metti l'app sul tuo telefono!

Finalmente abbiamo finito. Vai su file, crea impostazioni e fai clic su build. Apri Xcode e scegli la cartella che è stata creata dalla build. Scegli il tuo team di sviluppo e carica l'app sul tuo telefono! Potresti voler cambiare i colori delle particelle e dello skybox per soddisfare le tue esigenze. Fatemi sapere nei commenti se avete domande e grazie per la ricerca!

Consigliato: