Inhoudsopgave:

AR-portaal naar de ondersteboven van vreemde dingen: 10 stappen (met afbeeldingen)
AR-portaal naar de ondersteboven van vreemde dingen: 10 stappen (met afbeeldingen)

Video: AR-portaal naar de ondersteboven van vreemde dingen: 10 stappen (met afbeeldingen)

Video: AR-portaal naar de ondersteboven van vreemde dingen: 10 stappen (met afbeeldingen)
Video: Datascience in het Spoor #10 Bovenleiding monitoring 2024, November
Anonim
AR-portaal naar de ondersteboven van vreemdere dingen
AR-portaal naar de ondersteboven van vreemdere dingen
AR-portaal naar de ondersteboven van vreemdere dingen
AR-portaal naar de ondersteboven van vreemdere dingen

Dit Instructable zal gaan door het creëren van een augmented reality mobiele app voor de iPhone met een portaal dat leidt naar de ondersteboven van de Stranger Things. Je kunt het portaal binnengaan, rondlopen en weer naar buiten komen. Alles in het portaal kan alleen door het portaal worden gezien totdat je naar binnen loopt. Eenmaal binnen wordt alles overal weergegeven, totdat je terugloopt in de echte wereld. We zullen de Unity 3D-videogame-engine gebruiken met de Apple ARKit-plug-in. Alle software die we zullen gebruiken, kan gratis worden gedownload en gebruikt. Je hoeft geen expert te zijn om mee te doen, we zullen elke stap doorlopen!

Stap 1: Start een nieuw Unity-project

Start een nieuw Unity-project
Start een nieuw Unity-project

Download eerst Unity3D en zorg ervoor dat u de buildbestanden voor het IOS-platform installeert. U moet ook Xcode downloaden en u aanmelden voor een gratis Apple-ontwikkelaarsaccount. Je iPhone moet ook iOS 11 of hoger gebruiken. Vanaf vandaag 5 februari 2018 is IOS 11.3 uit, maar xCode 9.2 heeft er nog geen ondersteuningsbestanden voor. Dus als u de allernieuwste IOS-versie gebruikt, zorg er dan voor dat u de nieuwste Xcode-bètaversie downloadt van Apple. Developer.com.

Zodra je alle benodigde programma's hebt, open je Unity en start je een nieuw project, noem het wat je wilt. We hebben de Apple ARKit-plug-in nodig, zodat we de camera van onze telefoon kunnen gebruiken om de grond te detecteren en objecten op de vloer te plaatsen. Laten we dat nu importeren door naar het tabblad Asset Store te gaan en naar "ARKit" te zoeken. U moet een gratis Unity-account maken als u er nog geen heeft, en klik vervolgens op importeren om de plug-in te downloaden.

Navigeer naar de map met voorbeelden in de map ARKit en zoek de "UnityARKitScene". Dubbelklik erop om het te openen. We gaan deze scène als uitgangspunt gebruiken en vanaf hier verder bouwen. Met deze scène kunt u standaard de grond detecteren en wanneer u op het scherm tikt, wordt een kubus op die positie geplaatst.

Laten we eerst onze build-instellingen in het kwadraat krijgen, zodat we het later niet vergeten. Klik op bestand, bouw instellingen en verwijder alle scènes uit die lijst. Klik op open scènes toevoegen om onze huidige toe te voegen. Het laatste dat we hier moeten instellen, is in de spelerinstellingen naar de bundel-ID gaan en het formaat voor deze string is com. YourCompanyName. YourAppName, dus in mijn geval doe ik iets als com. MatthewHallberg. PortalTest.

Stap 2: Stel de scène in

Stel de scène in
Stel de scène in

Kijk eerst naar links en vind het spelobject genaamd "GeneratePlanes". Met dat gemarkeerd, kijk nu naar rechts en klik op het selectievakje om het uit te schakelen. Op deze manier hebben we niet de lelijke blauwe vierkanten die worden gegenereerd wanneer ARKit een grondvlak detecteert. Verwijder vervolgens het spelobject "RandomCube" omdat we dat niet in onze scène willen zien.

Nu moeten we eerst onze portaaldeuropening maken. Verwijder de kubus die een kind is van de "HitCubeParent". Klik met de rechtermuisknop en kies leeg spelobject maken. Hernoem het "Portaal". Klik nu met de rechtermuisknop op dat object en maak een kubus, dit maakt het een kind van de portal. Hernoem het "PostLeft" en dit wordt het linker bericht van onze portal. Schaal het zo dat de x 1 is, de y 28 is en de z één. Doe hetzelfde voor de juiste post. Maak nu de bovenste paal en schaal de y naar 14. Draai deze zijwaarts en verplaats hem zodanig dat hij de andere palen verbindt. Maak de hele portaalschaal 1,3 x 1,4 x 1.

Ga naar google en typ hout- of schorstextuur in. Download een van die afbeeldingen en sleep deze naar uw activamap in Unity. Sleep die afbeelding nu naar al uw portaalberichten.

Klik nogmaals op het "Portal"-object en klik rechts op component toevoegen. Voeg het script "UnityARHitTestExample" eraan toe. Er is daar een lege sleuf voor "Hit Transform", sleep het object "HitCubeParent" naar die sleuf.

Stap 3: Laten we wat deeltjes maken

Laten we wat deeltjes maken
Laten we wat deeltjes maken

Nu gaan we het Unity Particle-systeem gebruiken om een rook- en zwevend deeltjeseffect te maken voor in ons portaal. Ga naar Assets in de bovenste menubalk, standaard assets en importeer particle-systemen.

Maak twee lege game-objecten in je portal en noem de ene "SmokeParticles" en de andere "FloatingParticles".

Voeg een deeltjessysteemcomponent toe aan de rookdeeltjes.

Dit onderdeel heeft een heleboel opties, maar we hoeven er maar een paar te veranderen.

Verander de startkleur in iets donkerblauw met ongeveer 50% transparantie. Maak de emissiesnelheid 100. Binnenvorm, maak de straal.01. Verander in het renderergedeelte onderaan de minimale grootte naar.8 en de maximale grootte naar 5. Kies op de materiële component gewoon het rookmateriaal uit de lijst, maar we gaan dit later wijzigen.

Voeg nu een deeltjessysteem toe aan het spelobject zwevende deeltjes en stel de emissie in op 500. Stel de startlevensduur in op 2, de straal op 10, de minimale deeltjesgrootte op 0,01 en de maximale deeltjesgrootte op 0,015. Zet het materiaal voorlopig op standaard deeltje.

Neem ten slotte beide game-objecten en draai ze 90 graden op de x en til ze op in de lucht zodat ze naar de portaaldeur komen.

Stap 4: Het vertragen van de deeltjes

De deeltjes vertragen
De deeltjes vertragen

Omdat we willen dat deze deeltjes een groot gebied bestrijken maar ook langzaam bewegen, moeten we onze eigen voorbeeldfunctie creëren. Dus klik met de rechtermuisknop in de activamap en maak een nieuw C#-script aan en noem het "ParticleSample". Kopieer en plak deze code in:

met behulp van System. Collections;

met behulp van System. Collections. Generic; met behulp van UnityEngine; openbare klasse ParticleSample: MonoBehaviour { private ParticleSystem ps; // Gebruik dit voor initialisatie void Start () { ps = GetComponent (); StartCoroutine (SampleParticleRoutine ()); } IEnumerator SampleParticleRoutine(){ var main = ps.main; main.simulationSpeed = 1000f; ps. Speel (); opbrengst rendement nieuwe WaitForSeconds (.1f); main.simulationSpeed =.05f; } }

Sleep dit script nu naar elk van de game-objecten van je deeltjessysteem.

Stap 5: Het portaal maken

Het portaal maken!
Het portaal maken!

Nu moeten we de portal maken, dus klik met de rechtermuisknop op het portalgame-object en maak een quad. Schaal de quad zodat deze het hele portaal bedekt, dit wordt ons portaalvenster. Het eerste dat we eraan moeten toevoegen, is de portal-shader, hiermee worden alleen objecten weergegeven met een andere specifieke shader erop. Klik met de rechtermuisknop in de activamap en maak een nieuwe onverlichte arcering. Verwijder alles daar en plak deze code in:

Shader "Portaal/portaalvenster"

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

Klik met de rechtermuisknop in de hiërarchie en maak een nieuw materiaal aan, noem het PortalWindowMat, zoek in de vervolgkeuzelijst voor dit materiaal het portaalgedeelte en kies portaalvenster. Sleep dit materiaal naar je portal quad.

Stap 6: Deeltjesshaders

Deeltjes shaders
Deeltjes shaders

Klik nogmaals met de rechtermuisknop in de activamap en maak een nieuwe arcering. We moeten de shaders maken voor de deeltjes die in het portaal gaan. Vervang alle code door dit:

Shader "Portaal/Deeltjes" {

Eigenschappen { _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 } Categorie { Tags { "Queue"="Transparant" "IgnoreProjector"="True" "RenderType"="Transparant" "PreviewType"="Plane" } Blend SrcAlpha OneMinusSrcAlpha ColorMask RGB Cull Uit Verlichting Uit 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 "TexyCG.cD include "UnityCG.cD" vast4 _TintColor; struct appdata_t { float4 vertex: POSITIE; vaste4 kleur: KLEUR; float2 texcoord: TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2f { float4 vertex: SV_POSITION; vaste4 kleur: KLEUR; 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.kleur = v.kleur * _TintColor; o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); UNITY_TRANSFER_FOG(o, o.vertex); retour o; } UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); zweven _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 = verzadigen (_InvFade * (sceneZ-partZ)); i.kleur.a *= vervagen; #endif fixed4 col = 2.0f * i.color * tex2D(_MainTex, i.texcoord); UNITY_APPLY_FOG(i.fogCoord, col); terugkeer kleur; } ENDCG } } } }

Maak twee nieuwe materialen, een met de naam portalSmoke en een met de naam portalParticles.

Kies voor elk deze shader, uit de vervolgkeuzelijst, in portalen, deeltjes. Kies voor de rookdeeltjes een rooktextuur en voor de deeltjes de deeltjestextuur. Verander de kleur van de rook in een donkerder blauw met ongeveer 50% transparantie. Ga naar de renderercomponent van elk deeltjessysteem in uw portal en kies hun respectievelijke materialen die we zojuist hebben gemaakt.

Stap 7: Maak de Skybox

Maak de Skybox
Maak de Skybox

Om nu echt het omgekeerde type look te creëren, moeten we alles donkerblauw verven. Hiervoor zullen we een transparante skybox gebruiken, dus maak een nieuwe shader en plak deze code in:

Shader "Portal/portalSkybox" {

Eigenschappen { _Tint ("Tint Kleur", Kleur) = (.5,.5,.5,.5) [Gamma] _Belichting ("Belichting", Bereik (0, 8)) = 1.0 _Rotatie ("Rotatie", Bereik (0, 360)) = 0 [NoScaleOffset] _Tex ("Cubemap (HDR)", Kubus) = "grijs" {} _Stencil("StencilNum", int) = 6 } SubShader { Tags { "Wachtrij"="Achtergrond" "RenderType"="Background" "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; halve _Belichting; zweven _Rotatie; float3 RotateAroundYInDegrees (float3 vertex, float graden) { float alpha = graden * UNITY_PI / 180.0; drijvende sina, cosa; sincos (alfa, sina, cosa); float2x2 m = float2x2(cosa, -sina, sina, cosa); retourneer float3(mul(m, hoekpunt.xz), hoekpunt.y).xzy; } struct appdata_t { float4 vertex: POSITIE; 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 geroteerd = RotateAroundYInDegrees(v.vertex, _Rotation); o.vertex = UnityObjectToClipPos (gedraaid); o.texcoord = v.vertex.xyz; retour o; } fixed4 frag (v2f i): SV_Target { half4 tex = texCUBE (_Tex, i.texcoord); half3 c = DecodeerHDR (tex, _Tex_HDR); c = c * _Tint.rgb * unity_ColorSpaceDouble.rgb; c *= _Belichting; retourneer half4(c,.5); } ENDCG } } Terugval uit }

Maak nu een nieuw skybox-materiaal, noem het "PortalSkybox" en kies deze portalSkybox-shader in het portalmenu. Ga naar Venster, Verlichting, bovenaan en kies deze skybox die we zojuist hebben gemaakt. Ga naar de hoofdcamera en stel duidelijke vlaggen in op skybox. Terwijl we hier zijn, laten we enkele componenten aan onze camera toevoegen, zodat we botsingen kunnen detecteren. Voeg een starbody-component toe aan de camera en schakel het vinkje uit voor gebruik zwaartekracht. Voeg een box-collider toe en check on is trigger. Maak de box-colliders maat.5 x 1 x 4. Stel het uitknipvlak op de camera in op.01.

Stap 8: Portallogica

Portaal logica
Portaal logica

Het laatste wat we moeten doen is de logica creëren die onze portal bestuurt. Maak een nieuw C#-script en noem het PortalController.

met behulp van System. Collections;

met behulp van System. Collections. Generic; met behulp van UnityEngine; naamruimte UnityEngine. XR.iOS{ openbare klasse PortalController: MonoBehaviour { openbaar materiaal materialen; openbare MeshRenderer meshRenderer; openbare UnityARVideo UnityARVideo; private bool isInside = false; private bool isOutside = waar; // Gebruik dit voor initialisatie 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; isBinnen = waar; BinnenPortaal (); } } else { if (isInside) { isInside = false; isBuiten = waar; BuitenPortaal (); } } } void OutsidePortal(){ StartCoroutine (DelayChangeMat (3)); } void InsidePortal(){ StartCoroutine (DelayChangeMat (6)); } IEnumerator DelayChangeMat (int stencilNum) { UnityARVideo.shouldRender = false; opbrengst retour nieuwe WaitForEndOfFrame (); meshRenderer.enabled = onwaar; foreach (Materiaalmat in materialen) { mat. SetInt ("_Stencil", stencilNum); } opbrengst retourneer nieuwe WaitForEndOfFrame (); meshRenderer.enabled = waar; UnityARVideo.shouldRender = waar; } } }

Sleep dit nieuwe script naar uw portaalvenster. Dit zal ons in en uit het portaal laten gaan wanneer de botser op onze camera in botsing komt met het portaalvenster. Nu in de functie die alle materialen verandert, vertellen we de ARkit-plug-in om het frame niet te renderen, dus ga naar de hoofdcamera en open het UnityARVideo-script. Maak bovenaan een openbare bool shouldRender en stel deze in op true. Beneden in de functie OnPreRender() wikkel alles in een if-statement waarin alles binnenin alleen wordt uitgevoerd als ShouldRender waar is. Het hele script zou er als volgt uit moeten zien:

systeem gebruiken;

met behulp van System. Runtime. InteropServices; met behulp van UnityEngine; met behulp van UnityEngine. Rendering; naamruimte UnityEngine. XR.iOS { openbare klasse UnityARVideo: MonoBehaviour { openbaar materiaal m_ClearMaterial; [HideInInspector] openbare bool shouldRender = true; privé CommandBuffer m_VideoCommandBuffer; privé Texture2D _videoTextureY; privé Texture2D _videoTextureCbCr; privé Matrix4x4 _displayTransform; private bool bCommandBufferGeïnitialiseerd; public void Start() { UnityARSessionNativeInterface. ARFrameUpdatedEvent += UpdateFrame; bCommandBufferInitialized = false; } void UpdateFrame (UnityARCamera cam) { _displayTransform = nieuwe 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 = nieuwe CommandBuffer(); m_VideoCommandBuffer. Blit (null, BuiltinRenderTextureType. CurrentActive, m_ClearMaterial); GetComponent(). AddCommandBuffer(CameraEvent. BeforeForwardOpaque, m_VideoCommandBuffer); bCommandBufferInitialized = waar; } void OnDestroy () { GetComponent (). RemoveCommandBuffer (CameraEvent. BeforeForwardOpaque, m_VideoCommandBuffer); UnityARSessionNativeInterface. ARFrameUpdatedEvent -= UpdateFrame; bCommandBufferInitialized = false; } #if !UNITY_EDITOR public void OnPreRender() {if (shouldRender){ ARTextureHandles handvatten = UnityARSessionNativeInterface. GetARSessionNativeInterface (). GetARVideoTextureHandles(); if (handles.textureY == System. IntPtr. Zero || handles.textureCbCr == System. IntPtr. Zero) { return; } if (!bCommandBufferInitialized) { InitializeCommandBuffer (); } Resolutie currentResolution = Screen.currentResolution; // Textuur Y if (_videoTextureY == null) { _videoTextureY = Texture2D. CreateExternalTexture (currentResolution.width, currentResolution.height, TextureFormat. R8, false, false, (System. IntPtr)handles.textureY); _videoTextureY.filterMode = FilterMode. Bilineair; _videoTextureY.wrapMode = TextureWrapMode. Herhalen; 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. Bilineair; _videoTextureCbCr.wrapMode = TextureWrapMode. Herhalen; 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); } #stop als } }

Stap 9: Bijna klaar

Bijna klaar!
Bijna klaar!

Eindelijk, wanneer we op het scherm klikken en de portal plaatsen, willen we dat deze altijd naar ons gericht is. Ga hiervoor naar het script "UnityARHitTestExample" op de portal. Vervang alles binnen door dit:

systeem gebruiken;

met behulp van System. Collections. Generic; naamruimte UnityEngine. XR.iOS {publieke klasse UnityARHitTestExample: MonoBehaviour {public Transform m_HitTransform; openbare float maxRayDistance = 30.0f; public LayerMask collisionLayer = 1 <0) { foreach (var hitResult in hitResults) { Debug. Log ("Gekregen!"); 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 = nieuwe Vector3 (currAngle.x, transform.eulerAngles.y, currAngle.z); retourneer waar; } } retourneer onwaar; } // Update wordt eenmaal per frame aangeroepen void Update () { #if UNITY_EDITOR // we zullen dit script alleen aan de editorkant gebruiken, hoewel er niets is dat zou voorkomen dat het op het apparaat werkt als (Input. GetMouseButtonDown (0)) { Ray ray = Camera.main. ScreenPointToRay (Input.mousePosition); RaycastHit hit; // we zullen proberen een van de gameobjects van de plane collider te raken die zijn gegenereerd door de plug-in // effectief vergelijkbaar met het aanroepen van HitTest met ARHitTestResultType. ARHitTestResultTypeExistingPlaneUsingExtent if (Physics. Raycast (ray, out hit, maxRayDistance, collisionLayer)) { // we gaan de positie ophalen van het contactpunt 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)); // en de rotatie van de transformatie van de vliegtuigversneller 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-punt = nieuw ARPoint { x = screenPosition.x, y = screenPosition.y }; ARHitTestResultType resultTypes = { ARHitTestResultType. ARHitTestResultTypeExistingPlaneUsingExtent, // als je oneindige vlakken wilt gebruiken, gebruik dit: //ARHitTestResultType. ARHitTestResultTypeExistingTPlane, ARHitTestResultTypeExistingTPlane, ARHitTestResultTypeExistingTPlane, ARHitTestResultTypeExistingPlane, ARHitTestResultTypeTPlane, ARHitTestResultTypeExistingPlaneUsingExtent foreach (ARHitTestResultType resultType in resultTypes) {if (HitTestWithResultType (punt, resultaatType)) { return; } } } } #stop als } } }

Stap 10: Zet de app op je telefoon

Zet de app op je telefoon!
Zet de app op je telefoon!

Eindelijk zijn we klaar. Ga naar bestand, bouw instellingen en klik op bouwen. Open Xcode en kies de map die is gemaakt op basis van de build. Kies je ontwikkelteam en zet de app op je telefoon! Misschien wilt u de kleuren van de deeltjes en de skybox wijzigen om aan uw behoeften te voldoen. Laat het me weten in de comments als je vragen hebt en bedankt voor het kijken!

Aanbevolen: