Cuprins:

Portal AR către partea de sus a lucrurilor mai ciudate: 10 pași (cu imagini)
Portal AR către partea de sus a lucrurilor mai ciudate: 10 pași (cu imagini)

Video: Portal AR către partea de sus a lucrurilor mai ciudate: 10 pași (cu imagini)

Video: Portal AR către partea de sus a lucrurilor mai ciudate: 10 pași (cu imagini)
Video: Valeriu Coadă te învață cum să scapi într-o SITUAȚIE EXTREMĂ!! 😱😅 #tiktokromania #valeriucoada 2024, Noiembrie
Anonim
Portalul AR către partea de sus a lucrurilor mai ciudate
Portalul AR către partea de sus a lucrurilor mai ciudate
Portalul AR către partea de sus a lucrurilor mai ciudate
Portalul AR către partea de sus a lucrurilor mai ciudate

Acest Instructable va trece prin crearea unei aplicații mobile de realitate augmentată pentru iPhone, cu un portal care duce la capul în jos din Stranger Things. Puteți intra în portal, vă puteți plimba și vă puteți întoarce. Totul din interiorul portalului poate fi văzut doar prin portal până când intrați în interior. Odată ajuns înăuntru, totul se va reda peste tot, până când veți merge înapoi în lumea reală. Vom folosi motorul de jocuri video Unity 3D cu pluginul Apple ARKit. Toate software-urile pe care le vom folosi pot fi descărcate și utilizate gratuit. Nu trebuie să fiți un expert pentru a continua, vom parcurge fiecare pas!

Pasul 1: Porniți un nou proiect Unity

Porniți un nou proiect Unity
Porniți un nou proiect Unity

În primul rând, descărcați Unity3D și asigurați-vă că instalați fișierele de construcție pentru platforma IOS. De asemenea, va trebui să descărcați Xcode și să vă înscrieți pentru un cont gratuit de dezvoltator Apple. IPhone-ul dvs. va trebui, de asemenea, să ruleze IOS 11 sau mai mare. Începând de azi 5 februarie 2018, IOS 11.3 este disponibil, dar xCode 9.2 nu are încă fișiere de asistență pentru acesta. Deci, dacă rulați cea mai recentă versiune IOS, asigurați-vă că descărcați cea mai recentă versiune beta Xcode de la Apple. Developer.com.

Odată ce aveți toate programele necesare, deschideți Unity și începeți un nou proiect, numiți-l cum doriți. Vom avea nevoie de pluginul Apple ARKit, astfel încât să putem folosi camera telefonului nostru pentru a detecta solul și a pune obiecte pe podea. Să importăm acum accesând fila Magazin de active și să căutăm „ARKit”. Va trebui să creați un cont Unity gratuit dacă nu aveți deja unul, apoi faceți clic pe import pentru a obține pluginul.

Navigați la folderul de exemple din folderul ARKit și găsiți „UnityARKitScene”. Faceți dublu clic pe acesta pentru a-l deschide. Vom folosi această scenă ca punct de plecare și vom construi de aici. Această scenă implicit vă va permite să detectați solul și când atingeți ecranul, un cub va fi plasat în acea poziție.

Permiteți mai întâi să setăm setările noastre de construcție, astfel încât să nu uităm să o facem mai târziu. Faceți clic pe fișier, creați setări și eliminați toate scenele din lista respectivă. Faceți clic pe adăugați scene deschise pentru a adăuga actualul nostru. Ultimul lucru pe care trebuie să îl configurăm aici este că setările playerului merg la identificatorul de pachet și formatul pentru acest șir este com. YourCompanyName. YourAppName, deci în cazul meu fac ceva de genul com. MatthewHallberg. PortalTest.

Pasul 2: Configurați scena

Configurați scena
Configurați scena

Mai întâi aruncați o privire spre stânga și găsiți obiectul de joc numit „GeneratePlanes”. Cu aceasta evidențiată, priviți în dreapta acum și faceți clic pe caseta de selectare pentru a o dezactiva. În acest fel, nu avem urâtele pătrate albastre generate atunci când ARKit detectează un plan de sol. Apoi ștergeți obiectul de joc „RandomCube” deoarece nu vrem să vedem acest lucru în scena noastră.

Acum trebuie să creăm mai întâi ușa portalului nostru. Ștergeți cubul care este un copil al „HitCubeParent”. Faceți clic dreapta și alegeți creați un obiect de joc gol. Redenumiți-l „Portal”. Acum faceți clic dreapta pe acel obiect și creați un cub, acest lucru îl va face un copil al portalului. Redenumiți-l „PostLeft” și acesta va fi mesajul din stânga al portalului nostru. Scalați-l astfel încât x este 1, y este 28 și z este unul. Faceți același lucru pentru postarea corectă. Acum creați stâlpul de sus și scalați y la 14. Întoarceți-l lateral și mutați-l astfel încât să conecteze celelalte stâlpi. Faceți întreaga scară a portalului 1,3 x 1,4 x 1.

Accesați Google și tastați textura lemnului sau a scoarței. Descărcați una dintre aceste imagini și trageți-o în folderul dvs. de active din Unity. Acum trageți acea imagine pe toate postările de pe portal.

Faceți clic din nou pe obiectul „Portal” și faceți clic pe Adăugare componentă din dreapta. Adăugați scriptul „UnityARHitTestExample” la acesta. Există un slot gol pentru „Hit Transform”, trageți obiectul „HitCubeParent” în acel slot.

Pasul 3: Să facem niște particule

Să facem niște particule
Să facem niște particule

Acum vom folosi sistemul Unity Particle pentru a produce un efect de fum și particule plutitoare în interiorul portalului nostru. Accesați Activele din bara de meniu de sus, elementele standard și importați sistemele de particule.

Creați două obiecte de joc goale în portalul dvs. și numiți unul „SmokeParticles” și celălalt „FloatingParticles”.

Adăugați o componentă a sistemului de particule la particulele de fum.

Această componentă are o mulțime de opțiuni, dar trebuie doar să schimbăm câteva.

Schimbați culoarea inițială cu ceva albastru închis cu aproximativ 50% transparență. Faceți rata de emisie 100. În interiorul formei, faceți raza.01. În porțiunea de redare din partea de jos, schimbați dimensiunea minimă la.8 și dimensiunea maximă la 5. Pe componenta material alegeți doar materialul de fum din listă, dar vom schimba acest lucru mai târziu.

Adăugați acum un sistem de particule la obiectul de joc cu particule plutitoare și setați emisia la 500. Setați durata de viață a începutului la 2, raza la 10, dimensiunea minimă a particulelor la 0,01 și dimensiunea maximă a particulelor la 0,015. Setați materialul la particula implicită pentru moment.

În cele din urmă, luați ambele obiecte de joc și rotiți-le cu 90 de grade pe x și ridicați-le în aer, astfel încât acestea să emită în jos pe ușa portalului.

Pasul 4: încetinirea particulelor

Încetinirea particulelor
Încetinirea particulelor

Din moment ce dorim ca aceste particule să acopere o suprafață mare, dar să se miște și lent, trebuie să ne creăm propria funcție de eșantionare. Deci, faceți clic dreapta în folderul active și creați un nou script C # și numiți-l „ParticleSample”. Copiați și lipiți acest cod:

folosind System. Collections;

folosind System. Collections. Generic; folosind UnityEngine; clasă publică ParticleSample: MonoBehaviour {private ParticleSystem ps; // Utilizați acest lucru pentru inițializare void Start () {ps = GetComponent (); StartCoroutine (SampleParticleRoutine ()); } IEnumerator SampleParticleRoutine () {var main = ps.main; main.simulationSpeed = 1000f; ps. Play (); returnează nou WaitForSeconds (.1f); main.simulationSpeed =.05f; }}

Acum, trageți acest script pe fiecare dintre obiectele dvs. de joc ale sistemului de particule.

Pasul 5: Crearea portalului

Crearea portalului!
Crearea portalului!

Acum trebuie să creăm portalul, deci faceți clic dreapta pe obiectul jocului portal și creați un quad. Scalați quad-ul astfel încât să acopere întregul portal, acesta urmând să devină fereastra portalului nostru. Primul lucru pe care trebuie să-l adăugăm este shader-ul portal, acesta va reda numai obiecte cu alt shader specific pe ele. Faceți clic dreapta în folderul active și creați un nou shader neluminat. Eliminați tot ce este acolo și lipiți acest cod:

Shader "Portal / portalWindow"

{SubShader {Zwrite off Colormask 0 eliminat Stencil {Ref 1 Trecere înlocuire} Trecere {}}}

Faceți clic dreapta în ierarhie și creați un material nou, numiți-l PortalWindowMat, în meniul derulant pentru acest material găsiți secțiunea portal și alegeți fereastra portalului. Trageți acest material pe quad-ul portalului dvs.

Pasul 6: Umbrele de particule

Umbrele de particule
Umbrele de particule

Faceți clic din nou în dosarul active și creați un nou shader. Trebuie să facem umbrele pentru particulele care intră în portal. Înlocuiți tot codul cu acesta:

Shader „Portal / particule” {

Proprietăți {_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 {Taguri {"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 culoare: CULOARE; float2 texcoord: TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID}; struct v2f {float4 vertex: SV_POSITION; fix4 culoare: CULOARE; 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); retur 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, col); return col; } ENDCG}}}}

Creați două materiale noi, unul numit portalSmoke și unul numit portalParticles.

Pentru fiecare alegeți acest shader, din meniul derulant, în portaluri, particule. Pentru particulele de fum alegeți o textură de fum și pentru particule alegeți textura particulelor. Schimbați culoarea fumului într-un albastru mai închis, cu aproximativ 50% transparență. Accesați componenta de redare a fiecărui sistem de particule din portalul dvs. și alegeți materialele respective pe care tocmai le-am creat.

Pasul 7: Creați Skybox

Creați Skybox
Creați Skybox

Acum, pentru a crea cu adevărat tipul de aspect cu capul în jos, trebuie să nuanțăm totul în albastru închis. Pentru aceasta vom folosi un skybox transparent, așa că creați un nou shader și lipiți în acest cod:

Shader „Portal / portalSkybox” {

Proprietăți {_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) = "gri" {} _Stencil ("StencilNum", int) = 6} SubShader {Taguri {"Queue" = "Background" "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; jumătate _Expunere; float _Rotation; float3 RotateAroundYInDegrees (vârf float3, grade float) {float alfa = grade * 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 (rotit); o.texcoord = v.vertex.xyz; retur o; } fixed4 frag (v2f i): SV_Target {half4 tex = texCUBE (_Tex, i.texcoord); half3 c = DecodeHDR (tex, _Tex_HDR); c = c * _Tint.rgb * unitate_ColorSpaceDouble.rgb; c * = _Expunere; returnează jumătate4 (c,.5); } ENDCG}} Fallback Off}

Acum creați un nou material skybox, numiți-l „PortalSkybox” și alegeți acest shader portalSkybox din meniul portalului. Accesați fereastră, Iluminare, în partea de sus și alegeți această casetă pe care tocmai am creat-o. Mergeți la camera principală și setați steaguri clare la skybox. În timp ce suntem aici, permiteți adăugarea unor componente pe camera noastră, astfel încât să putem detecta coliziuni. Adăugați o componentă rigidă a camerei și debifați utilizarea gravitației. Adăugați un colizor de cutii și verificați dacă este declanșator. Faceți dimensiunea coliderelor cutiei.5 x 1 x 4. Setați planul de decupare al camerei la.01.

Pasul 8: Logica portalului

Logica portalului
Logica portalului

Ultimul lucru pe care trebuie să-l facem este să creăm logica care controlează portalul nostru. Creați un nou script C # și numiți-l PortalController.

folosind System. Collections;

folosind System. Collections. Generic; folosind UnityEngine; spațiu de nume UnityEngine. XR.iOS {public class PortalController: MonoBehaviour {public Material materiale; public MeshRenderer meshRenderer; public UnityARVideo UnityARVideo; private bool isInside = false; private bool isOutside = adevărat; // Utilizați acest lucru pentru inițializare 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 = adevărat; InsidePortal (); }} else {if (isInside) {isInside = false; isOutside = adevărat; OutsidePortal (); }}} void OutsidePortal () {StartCoroutine (DelayChangeMat (3)); } void InsidePortal () {StartCoroutine (DelayChangeMat (6)); } IEnumerator DelayChangeMat (int stencilNum) {UnityARVideo.shouldRender = false; returnează nou WaitForEndOfFrame (); meshRenderer.enabled = fals; foreach (Material mat în materiale) {mat. SetInt ("_Stencil", stencilNum); } returnează nou WaitForEndOfFrame (); meshRenderer.enabled = adevărat; UnityARVideo.shouldRender = adevărat; }}}

Trageți acest nou script pe fereastra portalului. Acest lucru ne va face tranziția în interiorul și în afara portalului ori de câte ori colizorul de pe camera noastră se ciocnește cu fereastra portalului. Acum, în funcția care schimbă toate materialele, îi spunem pluginului ARkit să nu redea cadrul, așa că mergeți la camera principală și deschideți scriptul UnityARVideo. Creați un bool public shouldRender în partea de sus și setați-l egal cu adevărat. În funcția OnPreRender (), înfășurați totul într-o instrucțiune if, unde totul din interior va rula numai dacă shouldRender este adevărat. Întregul script ar trebui să arate astfel:

utilizarea sistemului;

folosind System. Runtime. InteropServices; folosind UnityEngine; folosind UnityEngine. Rendering; spațiu de nume UnityEngine. XR.iOS {public class UnityARVideo: MonoBehaviour {public Material m_ClearMaterial; [HideInInspector] public bool shouldRender = true; private CommandBuffer m_VideoCommandBuffer; private Texture2D _videoTextureY; private Texture2D _videoTextureCbCr; private Matrix4x4 _displayTransform; private 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 = new CommandBuffer (); m_VideoCommandBuffer. Blit (nul, BuiltinRenderTextureType. CurrentActive, m_ClearMaterial); GetComponent (). AddCommandBuffer (CameraEvent. BeforeForwardOpaque, m_VideoCommandBuffer); bCommandBufferInitialized = adevărat; } void OnDestroy () {GetComponent (). RemoveCommandBuffer (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; } if (! bCommandBufferInitialized) {InitializeCommandBuffer (); } Rezoluție currentResolution = Screen.currentResolution; // Textură 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); } // Textură CbCr if (_videoTextureCbCr == null) {_videoTextureCbCr = Texture2D. CreateExternalTexture (currentResolution.width, currentResolution.height, TextureFormat. RG16, false, false, (System. IntPtr) handles.textureCb; _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); } #endif}}

Pasul 9: Aproape Gata

Aproape gata!
Aproape gata!

În cele din urmă, atunci când facem clic pe ecran și plasăm portalul, vrem să ne confrunte întotdeauna. Pentru aceasta, accesați scriptul „UnityARHitTestExample” de pe portal. Înlocuiți totul din interior cu acest lucru:

utilizarea sistemului;

folosind System. Collections. Generic; namespace UnityEngine. XR.iOS {public class UnityARHitTestExample: MonoBehaviour {public Transform m_HitTransform; float public maxRayDistance = 30.0f; public LayerMask collisionLayer = 1 <0) {foreach (var hitResult in hitResults) {Debug. Log ("Am fost lovit!"); 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); întoarcere adevărată; }} returnează fals; } // Actualizarea se numește o dată pe cadru nul Update () {#if UNITY_EDITOR // vom folosi acest script numai în partea de editor, deși nu există nimic care să-l împiedice să funcționeze pe dispozitiv dacă (Input. GetMouseButtonDown (0)) {Ray ray = Camera.main. ScreenPointToRay (Input.mousePosition); RaycastHit a lovit; // vom încerca să lovim unul dintre obiectele jocului avionului care a fost generat de plugin // efectiv similar cu apelarea HitTest cu ARHitTestResultType. ARHitTestResultTypeExistingPlaneUsingExtent if (Physics. Raycast (ray, out hit, maxRayDistance, collisionLayer)) {// vom obține poziția din punctul de contact 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 rotația de la transformarea coliderului plan 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); Punct ARPoint = ARPoint nou {x = screenPosition.x, y = screenPosition.y}; // Prioritizarea reults tipuri ARHitTestResultType resultTypes = {ARHitTestResultType. ARHitTestResultTypeExistingPlaneUsingExtent, // dacă doriți să utilizați avioane infinite folosi acest: //ARHitTestResultType. ARHitTestResultTypeExistingPlane, ARHitTestResultType. ARHitTestResultTypeHorizontalPlane, ARHitTestResultType. ARHitTestResultTypeFeaturePoint}; foreach (ARHitTestResultType resultType în resultTypes) {if (HitTestWithResultType (point, resultType)) {return; }}}} #endif}}}

Pasul 10: Puneți aplicația pe telefon

Puneți aplicația pe telefonul dvs.!
Puneți aplicația pe telefonul dvs.!

În cele din urmă am terminat. Mergeți la fișier, creați setări și faceți clic pe compilare. Deschideți Xcode și alegeți folderul care a fost creat din compilare. Alege-ți echipa de dezvoltare și pune aplicația pe telefon! Este posibil să doriți să schimbați culorile particulelor și a skybox-ului pentru a se potrivi nevoilor dumneavoastră. Spuneți-mi în comentarii dacă aveți întrebări și vă mulțumim că ați căutat!

Recomandat: