AR Portal to the Upside Down From Stranger Things: 10 Steps (med bilder)
AR Portal to the Upside Down From Stranger Things: 10 Steps (med bilder)

Video: AR Portal to the Upside Down From Stranger Things: 10 Steps (med bilder)

Video: AR Portal to the Upside Down From Stranger Things: 10 Steps (med bilder)
Video: Every Time Vecna Appeared In Seasons 1-3 | Stranger Things Deep Dive 2025, Januar
Anonim
AR Portal to the Upside Down From Stranger Things
AR Portal to the Upside Down From Stranger Things
AR Portal to the Upside Down From Stranger Things
AR Portal to the Upside Down From Stranger Things

Denne instruksen vil gå gjennom å lage en augmented reality -mobilapp for iPhone med en portal som fører til opp -ned fra Stranger Things. Du kan gå inn i portalen, gå rundt og komme ut igjen. Alt inne i portalen kan bare sees gjennom portalen til du går inn. Når du er inne, vil alt gjengis overalt, til du går tilbake til den virkelige verden. Vi vil bruke Unity 3D -videospillmotoren med Apple ARKit -plugin. All programvare vi skal bruke kan lastes ned og brukes gratis. Du trenger ikke å være ekspert for å følge med, vi går gjennom hvert trinn!

Trinn 1: Start et nytt enhetsprosjekt

Start et nytt enhetsprosjekt
Start et nytt enhetsprosjekt

Først må du laste ned Unity3D og sørge for å installere byggfilene for IOS -plattformen. Du må også laste ned Xcode og registrere deg for en gratis apputviklerkonto. IPhone -en din må også kjøre IOS 11 eller nyere. Fra og med i dag 5. februar 2018 er IOS 11.3 ute, men xCode 9.2 har ennå ikke støttefiler for det. Så hvis du kjører den nyeste IOS -versjonen, må du laste ned den nyeste betaversjonen av Xcode fra Apple. Developer.com.

Når du har alle nødvendige programmer, åpner du Unity og starter et nytt prosjekt, kall det hva du vil. Vi kommer til å trenge Apple ARKit -pluginet, slik at vi kan bruke telefonens kamera til å oppdage bakken og plassere objekter på gulvet. La oss importere det nå ved å gå til kategorien Asset Store og søke "ARKit". Du må opprette en gratis Unity -konto hvis du ikke allerede har en, og klikk deretter på import for å få pluginet.

Naviger til eksempler -mappen i ARKit -mappen og finn "UnityARKitScene." Dobbeltklikk på den for å åpne den. Vi skal bruke denne scenen som utgangspunkt og bygge videre herfra. Denne scenen lar deg som standard oppdage bakken, og når du trykker på skjermen, plasseres en kube i den posisjonen.

La oss først få bygningsinnstillingene kvadrat bort, så vi ikke glemmer å gjøre det senere. Klikk fil, bygg innstillinger og fjern alle scener fra listen. Klikk på legg til åpne scener for å legge til vår nåværende. Det siste vi trenger å sette opp her er i spillerinnstillingene, gå ned til bunt -ID og formatet for denne strengen er com. YourCompanyName. YourAppName, så i mitt tilfelle gjør jeg noe som com. MatthewHallberg. PortalTest.

Trinn 2: Sett opp scenen

Sett opp scenen
Sett opp scenen

Ta en titt til venstre og finn spillobjektet som heter "GeneratePlanes". Med det uthevet, se til høyre nå og klikk i avmerkingsboksen for å deaktivere det. På denne måten har vi ikke de stygge blå rutene som genereres når ARKit oppdager et bakkeplan. Slett deretter "RandomCube" -spillobjektet fordi vi ikke vil se det i scenen vår.

Nå må vi først lage portaldøren. Slett kuben som er et barn av "HitCubeParent". Høyreklikk og velg opprett tomt spillobjekt. Gi den nytt navn til "Portal". Høyreklikk på objektet og lag en kube, dette vil gjøre den til et barn av portalen. Gi nytt navn til "PostLeft", og dette vil være venstre innlegg i portalen vår. Skala den slik at x er 1 y er 28 og z er en. Gjør det samme for riktig innlegg. Lag nå den øverste stolpen og skala y til 14. Snu denne sidelengs og flytt den slik at den forbinder de andre stolpene. Lag hele portalskalaen 1,3 x 1,4 x 1.

Gå til google og skriv inn tre eller barktekstur. Last ned ett av disse bildene og dra det til mappen din i Unity. Dra bildet nå til alle portalinnleggene dine.

Klikk på "Portal" -objektet igjen, og klikk på legg til komponent til høyre. Legg til "UnityARHitTestExample" -skriptet til det. Det er et tomt spor der for "Hit Transform", dra "HitCubeParent" -objektet inn i sporet.

Trinn 3: La oss lage noen partikler

La oss lage noen partikler
La oss lage noen partikler

Nå skal vi bruke Unity Particle -systemet til å lage en røyk- og flytende partikkeleffekt for inne i portalen vår. Gå til eiendeler øverst i menylinjen, standard eiendeler og importpartikkelsystemer.

Lag to tomme spillobjekter inne i portalen, og kall den ene "SmokeParticles" og den andre "FloatingParticles."

Tilsett en partikkelsystemkomponent til røykpartiklene.

Denne komponenten har en rekke alternativer, men vi trenger bare å bytte et par.

Endre startfargen til noe mørkeblått med omtrent 50% gjennomsiktighet. Lag utslippshastigheten 100. Innvendig form, lag radius.01. I gjengivelsesdelen nederst endrer du min størrelse til.8 og maks størrelse til 5. På materialkomponenten velger du bare røykmaterialet fra listen, men vi skal endre dette senere.

Legg til et partikkelsystem i spillobjektet for flytende partikler nå og sett utslippet til 500. Sett startlevetiden til 2, radius til 10, min partikkelstørrelse til.01 og maks partikkelstørrelse til.015. Sett materialet til standardpartikkel for øyeblikket.

Ta til slutt begge spillobjektene og roter dem med 90 grader på x og løft dem opp i luften slik at de slipper ned på portdøren.

Trinn 4: Bremse partiklene

Bremser partiklene
Bremser partiklene

Siden vi vil at disse partiklene skal dekke et stort område, men også bevege seg sakte, må vi lage vår egen prøvefunksjon. Så høyreklikk i ressursmappen og opprett et nytt C# -skript og kall det "ParticleSample." Kopier og lim inn denne koden:

bruk av System. Collections;

bruker System. Collections. Generic; bruker UnityEngine; offentlig klasse ParticleSample: MonoBehaviour {private ParticleSystem ps; // Bruk dette for å initialisere 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; }}

Dra nå dette skriptet til hvert av dine partikkelsystemspillobjekter.

Trinn 5: Opprette portalen

Oppretter portalen!
Oppretter portalen!

Nå må vi opprette portalen, så høyreklikk på portalspillobjektet og lag en quad. Skaler firhjulingen slik at den dekker hele portalen, dette kommer til å bli vårt portalvindu. Det første vi må legge til er portalshader, dette vil bare gjengi objekter med en annen spesifikk shader på. Høyreklikk i ressursmappen og opprett en ny uopplyst skygge. Fjern alt der inne og lim inn denne koden:

Shader "Portal/portalWindow"

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

Høyreklikk i hierarkiet og opprett et nytt materiale, kall det PortalWindowMat, finn portalseksjonen i rullegardinlisten for dette materialet, og velg portalvindu. Dra dette materialet til din portal quad.

Trinn 6: Particle Shaders

Particle Shaders
Particle Shaders

Høyreklikk i ressursmappen igjen og opprett en ny skygge. Vi må lage shaders for partiklene som går inne i portalen. Erstatt all koden med dette:

Shader "Portal/Particles" {

Egenskaper {_TintColor ("Tint Color", Color) = (0.5, 0.5, 0.5, 0.5) _MainTex ("Particle Texture", 2D) = "white" {} _InvFade ("Soft Particles Factor", Range (0.01, 3.0)) = 1.0 _Stencil ("stencil", int) = 6} Kategori {Tags {"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" fixed4 _TintColor; struct appdata_t {float4 toppunkt: POSISJON; fixed4 farge: COLOR; float2 texcoord: TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID}; struct v2f {float4 toppunkt: SV_POSITION; fixed4 farge: 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); returnere 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 *= fade; #endif fixed4 col = 2.0f * i.color * tex2D (_MainTex, i.texcoord); UNITY_APPLY_FOG (i.fogCoord, kol); retur col; } ENDCG}}}}}

Lag to nye materialer, ett som kalles portalSmoke, og ett som kalles portalParticles.

Velg hver skyggelegger, fra rullegardinmenyen, i portaler, partikler. For røykpartiklene velger du en røyktekstur og for partiklene velger du partikkelstrukturen. Endre fargen på røyken til en mørkere blå med omtrent 50% gjennomsiktighet. Gå til gjengivelseskomponenten til hvert partikkelsystem i portalen og velg deres respektive materialer som vi nettopp har opprettet.

Trinn 7: Lag Skybox

Lag Skybox
Lag Skybox

For å virkelig skape den opp -ned -typen, må vi farge alt mørkt blått. For dette bruker vi en gjennomsiktig skybox, så lag en ny skyggelegger og lim inn denne koden:

Shader "Portal/portalSkybox" {

Egenskaper {_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) = "grå" {} _Stencil ("StencilNum", int) = 6} SubShader {Tags {"Queue" = "Background" "RenderType" = "Bakgrunn" "PreviewType" = "Skybox"} Slå av 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; halv _Eksponering; float _Rotasjon; float3 RotateAroundYInDegrees (float3 toppunkt, flytegrader) {float alfa = grader * UNITY_PI / 180.0; flyte 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 toppunkt: POSISJON; UNITY_VERTEX_INPUT_INSTANCE_ID}; struct v2f {float4 toppunkt: 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 (rotert); o.texcoord = v.vertex.xyz; returnere 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 *= _Eksponering; returhalv4 (c,.5); } ENDCG}} Fallback Off}

Lag nå et nytt skybox -materiale, kall det "PortalSkybox" og velg denne portalSkybox -skyggeleggeren fra portalmenyen. Gå til Window, Lighting, øverst og velg denne skyboxen vi nettopp har opprettet. Gå til hovedkameraet og sett klare flagg til skybox. Mens vi er her, kan vi legge til noen komponenter på kameraet vårt, slik at vi kan oppdage kollisjoner. Legg til en stiv kroppskomponent i kameraet og fjern merket for bruk av tyngdekraften. Legg til en bokskollider og sjekk om utløseren er. Lag boksen kolliderer størrelse. 5 x 1 x 4. Sett klippeplanet på kameraet til.01.

Trinn 8: Portal Logic

Portal logikk
Portal logikk

Det siste vi må gjøre er å lage logikken som styrer portalen vår. Lag et nytt C# -skript og kall det PortalController.

bruk av System. Collections;

bruker System. Collections. Generic; bruker UnityEngine; navneområde UnityEngine. XR.iOS {public class PortalController: MonoBehaviour {public Material materials; offentlig MeshRenderer meshRenderer; offentlig UnityARVideo UnityARVideo; private bool isInside = false; private bool isOutside = true; // Bruk dette for initialisering av ugyldig Start () {OutsidePortal (); } ugyldig 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 (); }} annet {if (isInside) {isInside = false; isOutside = true; OutsidePortal (); }}} ugyldig OutsidePortal () {StartCoroutine (DelayChangeMat (3)); } ugyldig InsidePortal () {StartCoroutine (DelayChangeMat (6)); } IEnumerator DelayChangeMat (int stencilNum) {UnityARVideo.shouldRender = false; yield return new WaitForEndOfFrame (); meshRenderer.enabled = false; foreach (Materialmatte i materialer) {mat. SetInt ("_Stencil", stencilNum); } gi avkastning ny WaitForEndOfFrame (); meshRenderer.enabled = true; UnityARVideo.shouldRender = true; }}}

Dra dette nye skriptet til portalvinduet. Dette vil overføre oss inn og ut av portalen når kollidereren på kameraet vårt kolliderer med portalvinduet. Nå i funksjonen som endrer alt materialet, forteller vi ARkit -pluginet at det ikke skal gjengi rammen, så gå til hovedkameraet og åpne UnityARVideo -skriptet. Lag en offentlig bool shouldRender øverst og sett den lik sann. Nede i OnPreRender () -funksjonen pakk alt inn i en if -setning der alt inne bare vil kjøre hvis shouldRender er sant. Hele skriptet skal se slik ut:

bruker System;

bruker System. Runtime. InteropServices; bruker UnityEngine; bruker UnityEngine. Rendering; navneområde UnityEngine. XR.iOS {public class UnityARVideo: MonoBehaviour {public Material m_ClearMaterial; [HideInInspector] offentlig bool shouldRender = true; private CommandBuffer m_VideoCommandBuffer; privat Texture2D _videoTextureY; private Texture2D _videoTextureCbCr; private Matrix4x4 _displayTransform; private bool bCommandBufferInitialized; public void Start () {UnityARSessionNativeInterface. ARFrameUpdatedEvent += UpdateFrame; bCommandBufferInitialized = false; } ugyldig UpdateFrame (UnityARCamera -kamera) {_displayTransform = ny 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 = ny CommandBuffer (); m_VideoCommandBuffer. Blit (null, BuiltinRenderTextureType. CurrentActive, m_ClearMaterial); GetComponent (). AddCommandBuffer (CameraEvent. BeforeForwardOpaque, m_VideoCommandBuffer); bCommandBufferInitialized = true; } ugyldig OnDestroy () {GetComponent (). FjernCommandBuffer (CameraEvent. BeforeForwardOpaque, m_VideoCommandBuffer); UnityARSessionNativeInterface. ARFrameUpdatedEvent -= UpdateFrame; bCommandBufferInitialized = false; } #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; } hvis (! bCommandBufferInitialized) {InitializeCommandBuffer (); } Resolution currentResolution = Screen.currentResolution; // Tekstur Y hvis (_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.textureCbC); _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; } offentlig tomrom 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); } #slutt om } }

Trinn 9: Nesten ferdig

Nesten ferdig!
Nesten ferdig!

Til slutt når vi klikker på skjermen og plasserer portalen, vil vi at den alltid skal stå overfor oss. For å gjøre dette, gå til "UnityARHitTestExample" -skriptet på portalen. Bytt alt innvendig med dette:

bruker System;

bruker System. Collections. Generic; navneområde UnityEngine. XR.iOS {public class UnityARHitTestExample: MonoBehaviour {public Transform m_HitTransform; offentlig float maxRayDistance = 30.0f; public LayerMask collisionLayer = 1 <0) {foreach (var hitResult in 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. ######}}: {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 = ny Vector3 (currAngle.x, transform.eulerAngles.y, currAngle.z); returner sant; }} returner false; } // Oppdatering kalles én gang per ramme ugyldig oppdatering () {#if UNITY_EDITOR // vi vil bare bruke dette skriptet på redaktørsiden, selv om det ikke er noe som kan hindre det i å fungere på enheten hvis (Input. GetMouseButtonDown (0)) {Ray ray = Camera.main. ScreenPointToRay (Input.mousePosition); RaycastHit slo; // vi skal prøve å treffe et av flykollider -spillobjektene som ble generert av programtillegget // som faktisk ligner på å ringe HitTest med ARHitTestResultType. ARHitTestResultTypeExistingPlaneUsingExtent if (Physics. Raycast (ray, out hit, maxRayDistance, collisionLayer)) {// vi skal få posisjonen fra kontaktpunktet 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)); // og rotasjonen fra transformasjonen av flykollideren 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 -punkt = nytt ARPoint {x = screenPosition.x, y = screenPosition.y}; // Prioriter reults typer ARHitTestResultType resultTypes = {ARHitTestResultType. ARHitTestResultTypeExistingPlaneUsingExtent, // hvis du ønsker å bruke uendelig plan bruke denne: //ARHitTestResultType. ARHitTestResultTypeExistingPlane, ARHitTestResultType. ARHitTestResultTypeHorizontalPlane, ARHitTestResultType. ARHitTestResultTypeFeaturePoint}; foreach (ARHitTestResultType resultType in resultTypes) {if (HitTestWithResultType (point, resultType)) {return; } } } } #slutt om } } }

Trinn 10: Sett appen på telefonen

Sett appen på telefonen din!
Sett appen på telefonen din!

Endelig er vi ferdige. Gå til filen, bygg innstillinger og klikk på bygge. Åpne Xcode og velg mappen som ble opprettet fra bygningen. Velg ditt utviklingsteam og legg appen på telefonen! Det kan være lurt å endre fargene på partiklene og skyboxen for å passe dine behov. Gi meg beskjed i kommentarene hvis du har spørsmål og takk for at du så!