Portal AR ke Upside Down From Stranger Things: 10 Langkah (dengan Gambar)
Portal AR ke Upside Down From Stranger Things: 10 Langkah (dengan Gambar)

Video: Portal AR ke Upside Down From Stranger Things: 10 Langkah (dengan Gambar)

Video: Portal AR ke Upside Down From Stranger Things: 10 Langkah (dengan Gambar)
Video: How to Draw The DEMOGORGON (Stranger Things) | Narrated Easy Step-by-Step Tutorial 2025, Januari
Anonim
Portal AR ke Terbalik Dari Hal Asing
Portal AR ke Terbalik Dari Hal Asing
Portal AR ke Terbalik Dari Hal Asing
Portal AR ke Terbalik Dari Hal Asing

Instruksi ini akan melalui pembuatan aplikasi seluler augmented reality untuk iPhone dengan portal yang mengarah ke terbalik dari Stranger Things. Anda dapat masuk ke dalam portal, berjalan-jalan, dan kembali keluar. Segala sesuatu di dalam portal hanya dapat dilihat melalui portal sampai Anda berjalan masuk. Begitu masuk, semuanya akan merender di mana-mana, sampai Anda berjalan kembali ke dunia nyata. Kami akan menggunakan mesin video game Unity 3D dengan plugin Apple ARKit. Semua perangkat lunak yang akan kita gunakan dapat diunduh dan digunakan secara gratis. Anda tidak perlu menjadi ahli untuk mengikuti, kami akan melalui setiap langkah!

Langkah 1: Mulai Proyek Persatuan Baru

Mulai Proyek Persatuan Baru
Mulai Proyek Persatuan Baru

Pertama, unduh Unity3D dan pastikan untuk menginstal file build untuk platform iOS. Anda juga perlu mengunduh Xcode dan mendaftar untuk mendapatkan akun pengembang apel gratis. IPhone Anda juga harus menjalankan iOS 11 atau lebih tinggi. Pada hari ini 5 Februari 2018, IOS 11.3 keluar tetapi xCode 9.2 belum memiliki file dukungan untuk itu. Jadi jika Anda menjalankan versi iOS terbaru, pastikan untuk mengunduh versi beta Xcode terbaru dari Apple. Developer.com.

Setelah Anda memiliki semua program yang diperlukan, buka Unity dan mulai proyek baru, beri nama apa pun yang Anda inginkan. Kami akan membutuhkan plugin Apple ARKit sehingga kami dapat menggunakan kamera ponsel kami untuk mendeteksi tanah dan menempatkan objek di lantai. Mari impor sekarang dengan membuka tab Asset Store dan cari "ARKit". Anda perlu membuat akun Unity gratis jika Anda belum memilikinya, lalu klik impor untuk mendapatkan plugin.

Arahkan ke folder contoh di folder ARKit dan temukan "UnityARKitScene." Klik dua kali itu untuk membukanya. Kami akan menggunakan adegan ini sebagai titik awal dan membangun dari sini. Adegan ini secara default akan memungkinkan Anda untuk mendeteksi tanah dan ketika Anda mengetuk layar, sebuah kubus akan ditempatkan di posisi itu.

Pertama-tama mari kita perbaiki pengaturan build agar kita tidak lupa melakukannya nanti. Klik file, buat pengaturan dan hapus semua adegan dari daftar itu. Klik tambahkan adegan terbuka untuk menambahkan adegan kami saat ini. Hal terakhir yang perlu kita siapkan di sini adalah dalam pengaturan pemutar turun ke pengidentifikasi bundel dan format untuk string ini adalah com. YourCompanyName. YourAppName, jadi dalam kasus saya, saya melakukan sesuatu seperti com. MatthewHallberg. PortalTest.

Langkah 2: Atur Adegan

Mengatur Adegan
Mengatur Adegan

Pertama lihat ke kiri dan temukan objek game yang disebut "GeneratePlanes". Dengan itu disorot, lihat ke kanan sekarang dan klik kotak centang untuk menonaktifkannya. Dengan cara ini kita tidak memiliki kotak biru jelek yang dihasilkan ketika ARKit mendeteksi bidang tanah. Selanjutnya hapus objek game "RandomCube" karena kita tidak ingin melihatnya di scene kita.

Sekarang kita harus terlebih dahulu membuat pintu portal kita. Hapus kubus yang merupakan anak dari "HitCubeParent". Klik kanan dan pilih buat objek game kosong. Ganti namanya menjadi "Portal". Sekarang klik kanan pada objek itu dan buat kubus, ini akan menjadikannya anak dari portal. Ubah namanya menjadi "PostLeft" dan ini akan menjadi pos kiri portal kami. Skala itu sehingga x adalah 1 y adalah 28 dan z adalah satu. Lakukan hal yang sama untuk posting yang benar. Sekarang buat tiang atas dan skala y menjadi 14. Putar ini ke samping dan pindahkan sedemikian rupa sehingga menghubungkan pos lainnya. Buat seluruh portal berskala 1,3 x 1,4 x 1.

Buka google dan ketik tekstur kayu atau kulit kayu. Unduh salah satu gambar itu dan seret ke folder aset Anda di Unity. Sekarang seret gambar itu ke semua posting portal Anda.

Klik pada objek "Portal" lagi dan klik tambahkan komponen di sebelah kanan. Tambahkan skrip "UnityARHitTestExample" ke dalamnya. Ada slot kosong di sana untuk "Hit Transform", seret objek "HitCubeParent" ke dalam slot itu.

Langkah 3: Mari Membuat Beberapa Partikel

Mari Membuat Beberapa Partikel
Mari Membuat Beberapa Partikel

Sekarang kita akan menggunakan sistem Unity Particle untuk membuat asap dan efek partikel mengambang di dalam portal kita. Buka Aset di bilah menu atas, aset standar, dan sistem partikel impor.

Buat dua objek game kosong di dalam portal Anda dan panggil satu "SmokeParticles" dan yang lainnya "FloatingParticles."

Tambahkan komponen sistem partikel ke partikel asap.

Komponen ini memiliki banyak pilihan tetapi kita hanya perlu mengubah beberapa.

Ubah warna awal menjadi biru tua dengan transparansi sekitar 50%. Buat laju emisi 100. Bentuk bagian dalam, buat radius.01. Di bagian renderer di bagian bawah ubah ukuran min menjadi.8 dan ukuran maksimal menjadi 5. Pada komponen material pilih saja material asap dari daftar, tapi kita akan mengubahnya nanti.

Tambahkan sistem partikel ke objek permainan partikel mengambang sekarang dan atur emisi ke 500. Setel masa pakai awal ke 2, radius ke 10, ukuran partikel min ke.01, dan ukuran partikel maks ke.015. Atur material ke partikel default untuk saat ini.

Terakhir, ambil kedua objek permainan dan putar 90 derajat pada x dan angkat ke udara sehingga terpancar ke bawah ke pintu portal.

Langkah 4: Memperlambat Partikel

Memperlambat Partikel
Memperlambat Partikel

Karena kita ingin partikel-partikel ini mencakup area yang luas tetapi juga bergerak lambat, kita perlu membuat fungsi sampel kita sendiri. Jadi klik kanan di folder assets dan buat skrip C# baru dan beri nama "ParticleSample." Salin dan tempel dalam kode ini:

menggunakan System. Collections;

menggunakan System. Collections. Generic; menggunakan UnityEngine; public class ParticleSample: MonoBehaviour { private ParticleSystem ps; // Gunakan ini untuk inisialisasi void Start() { ps = GetComponent(); StartCoroutine (SampleParticleRoutine ()); } IEnumerator SampleParticleRoutine(){ var main = ps.main; main.simulationSpeed = 1000f; ps. Mainkan (); hasil kembalikan WaitForSeconds baru (.1f); main.simulationSpeed =.05f; } }

Sekarang seret skrip ini ke setiap objek permainan sistem partikel Anda.

Langkah 5: Membuat Portal

Membuat Portalnya!
Membuat Portalnya!

Sekarang kita perlu membuat portal jadi klik kanan pada objek game portal dan buat quad. Skala quad sehingga menutupi seluruh portal, ini akan menjadi jendela portal kita. Hal pertama yang perlu kita tambahkan adalah portal shader, ini hanya akan membuat objek dengan shader khusus lainnya. Klik kanan di folder aset dan buat shader gelap baru. Hapus semua yang ada di sana dan rekatkan dalam kode ini:

Shader "Portal/portalWindow"

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

Klik kanan di hierarki dan buat materi baru, sebut saja PortalWindowMat, di dropdown untuk materi ini temukan bagian portal, dan pilih jendela portal. Seret materi ini ke quad portal Anda.

Langkah 6: Partikel Shader

Partikel Shader
Partikel Shader

Klik kanan di folder aset lagi dan buat shader baru. Kita perlu membuat shader untuk partikel yang masuk ke dalam portal. Ganti semua kode dengan ini:

Shader "Portal/Partikel" {

Properties { _TintColor ("Tint Color", Color) = (0,5, 0,5, 0,5, 0,5) _MainTex ("Tekstur Partikel", 2D) = "putih" {} _InvFade ("Faktor Partikel Lunak", Rentang (0,01, 3.0)) = 1.0 _Stencil("stencil", int) = 6 } Kategori { Tag { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" } Blend SrcAlpha OneMinusSrcAlpha ColorMask RGB Cull Off Lighting Mati ZWrite Off SubShader { Stencil{ Ref 1 Comp[_Stencil] } Lulus { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 2.0 #pragma multi_compile_particles #pragma multi_compile_fog #include "UnityCG.cginc" sampler2D _MainTex2D; fixed4 _TintColor; struct appdata_t { float4 vertex: POSISI; fixed4 warna: WARNA; float2 texcoord: TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2f { float4 simpul: SV_POSITION; fixed4 warna: WARNA; 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); kembali o; } UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); mengapung _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 = jenuh (_InvFade * (sceneZ-partZ)); i.color.a *= memudar; #endif fixed4 col = 2.0f * i.color * tex2D(_MainTex, i.texcoord); UNITY_APPLY_FOG(i.fogCoord, col); kembali kol; } ENDCG } } } }

Buat dua materi baru, satu disebut portalSmoke, dan satu lagi disebut portalParticles.

Untuk masing-masing pilih shader ini, dari drop down, di portal, partikel. Untuk partikel asap pilih tekstur asap dan untuk partikel pilih tekstur partikel. Ubah warna asap menjadi biru gelap dengan transparansi sekitar 50%. Buka komponen penyaji dari setiap sistem partikel di portal Anda dan pilih bahannya masing-masing yang baru saja kita buat.

Langkah 7: Buat Skybox

Buat Skybox
Buat Skybox

Sekarang untuk benar-benar menciptakan tipe tampilan terbalik, kita harus mewarnai semuanya menjadi biru tua. Untuk ini kita akan menggunakan skybox transparan jadi buat shader baru dan tempel kode ini:

Shader "Portal/portalSkybox" {

Properties { _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) = "abu-abu" {} _Stencil("StencilNum", int) = 6 } SubShader { Tag { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" } Pisahkan ZWrite Off Blend SrcAlpha OneMinusSrcAlpha Stencil{ Ref 1 Comp[_Stencil] } Lulus { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 2.0 #include "UnityCG.cginc" samplerCUBE _Tex; half4 _Tex_HDR; half4 _Warna; setengah _Eksposur; float _Rotasi; float3 RotateAroundYInDegrees (float3 vertex, float derajat) { float alpha = derajat * UNITY_PI / 180.0; mengapung 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: POSISI; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2f { float4 simpul: 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(diputar); o.texcoord = v.vertex.xyz; kembali o; } frag tetap4 (v2f i): SV_Target { half4 tex = texCUBE (_Tex, i.texcoord); half3 c = DecodeHDR (tex, _Tex_HDR); c = c * _Tint.rgb * unity_ColorSpaceDouble.rgb; c *= _Paparan; kembali setengah4(c,.5); } ENDCG } } Pengunduran Mati }

Sekarang buat material skybox baru, beri nama "PortalSkybox" dan pilih portalSkybox shader ini dari menu portal. Pergi ke Window, Lighting, di bagian atas dan pilih skybox yang baru saja kita buat. Buka kamera utama dan atur bendera yang jelas ke skybox. Sementara kita di sini mari kita tambahkan beberapa komponen pada kamera kita sehingga kita dapat mendeteksi tabrakan. Tambahkan komponen bodi kaku ke kamera dan hapus centang gunakan gravitasi. Tambahkan penumbuk kotak dan centang pemicunya. Buat ukuran kotak tumbruk.5 x 1 x 4. Atur bidang kliping pada kamera ke.01.

Langkah 8: Logika Portal

Logika Portal
Logika Portal

Hal terakhir yang perlu kita lakukan adalah membuat logika yang mengontrol portal kita. Buat skrip C# baru dan beri nama PortalController.

menggunakan System. Collections;

menggunakan System. Collections. Generic; menggunakan UnityEngine; namespace UnityEngine. XR.iOS{ kelas publik PortalController: MonoBehaviour { Materi publik materi; MeshRenderer meshRenderer publik; UnityARVideo UnityARVideo publik; private bool isInside = false; private bool isOutside = true; // Gunakan ini untuk inisialisasi 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 = benar; InsidePortal(); } } else { if (isInside) { isInside = false; isOutside = benar; LuarPortal(); } } } void OutsidePortal(){ StartCoroutine (DelayChangeMat (3)); } void InsidePortal(){ StartCoroutine (DelayChangeMat (6)); } IEnumerator DelayChangeMat(int stencilNum){ UnityARVideo.shouldRender = false; hasilkan kembalikan WaitForEndOfFrame baru (); meshRenderer.enabled = salah; foreach (Material tikar dalam bahan) { mat. SetInt ("_Stencil", stencilNum); } hasilkan kembali WaitForEndOfFrame baru (); meshRenderer.enabled = benar; UnityARVideo.shouldRender = true; } } }

Seret skrip baru ini ke jendela portal Anda. Ini akan mentransisikan kita masuk dan keluar dari portal setiap kali penumbuk di kamera kita bertabrakan dengan jendela portal. Sekarang dalam fungsi yang mengubah semua materi, kami memberi tahu plugin ARkit untuk tidak membuat bingkai, jadi buka kamera utama dan buka skrip UnityARVideo. Buat bool publik shouldRender di bagian atas dan atur sama dengan true. Turun di fungsi OnPreRender() bungkus semuanya dalam pernyataan if di mana semua yang ada di dalamnya hanya akan berjalan jika shouldRender benar. Seluruh skrip akan terlihat seperti ini:

menggunakan Sistem;

menggunakan System. Runtime. InteropServices; menggunakan UnityEngine; menggunakan UnityEngine. Rendering; namespace UnityEngine. XR.iOS { kelas publik UnityARVideo: MonoBehaviour { Materi publik m_ClearMaterial; [HideInInspector] public bool shouldRender = true; CommandBuffer pribadi m_VideoCommandBuffer; Texture2D pribadi _videoTextureY; Texture2D pribadi _videoTextureCbCr; Matrix4x4 pribadi _displayTransform; bool pribadi 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(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 handles = UnityARSessionNativeInterface. GetARSessionNativeInterface (). GetARVideoTextureHandles(); if (handles.textureY == System. IntPtr. Zero || handles.textureCbCr == System. IntPtr. Zero) { kembali; } if (!bCommandBufferInitialized) { InitializeCommandBuffer(); } Resolusi currentResolution = Screen.currentResolution; // Tekstur 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); } #berakhir jika } }

Langkah 9: Hampir Selesai

Hampir selesai!
Hampir selesai!

Akhirnya ketika kita mengklik layar dan menempatkan portal yang kita inginkan untuk selalu menghadap kita. Untuk melakukannya, buka skrip "UnityARHitTestExample" di portal. Ganti semua yang ada di dalam dengan ini:

menggunakan Sistem;

menggunakan System. Collections. Generic; namespace UnityEngine. XR.iOS { public class UnityARHitTestTestContoh: MonoBehaviour { publik Transform m_HitTransform; float publik maxRayDistance = 30.0f; public LayerMask collisionLayer = 1 < 0) { foreach (var hitResult in hitResults) { Debug. Log ("Mendapat 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 = new Vector3 (currAngle.x, transform.eulerAngles.y, currAngle.z); kembali benar; } } mengembalikan salah; } // Update dipanggil sekali per frame void Update () { #if UNITY_EDITOR //kita hanya akan menggunakan skrip ini di sisi editor, meskipun tidak ada yang akan mencegahnya bekerja pada perangkat jika (Input. GetMouseButtonDown (0)) { Ray ray = Camera.main. ScreenPointToRay (Input.mousePosition); RaycastHit hit; //kita akan mencoba untuk mengenai salah satu objek game penumbuk pesawat yang dihasilkan oleh plugin //secara efektif mirip dengan memanggil HitTest dengan ARHitTestResultType. ARHitTestResultTypeExistingPlaneUsingExtent if (Physics. Raycast (ray, out hit, maxRayDistance, collisionLayer)) { // kita akan mendapatkan posisi dari titik kontak 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)); //dan rotasi dari transformasi penumbuk bidang 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 point = ARPoint baru { x = screenPosition.x, y = screenPosition.y }; //prioritaskan tipe reults ARHitTestResultType resultTypes = { ARHitTestResultType. ARHitTestResultTypeExistingPlaneUsingExtent, // jika Anda ingin menggunakan pesawat tak terbatas gunakan ini: //ARHitTestResultType. ARHitTestResultType. TRHestResultTypeExistingPlane, ARHitTestRestResult foreach (ARHitTestResultType resultType di resultTypes) { if (HitTestWithResultType (point, resultType)) { kembali; } } } } #berakhir jika } } }

Langkah 10: Letakkan Aplikasi di Ponsel Anda

Letakkan Aplikasi di Ponsel Anda!
Letakkan Aplikasi di Ponsel Anda!

Akhirnya kita selesai. Buka file, bangun pengaturan dan klik build. Buka Xcode dan pilih folder yang dibuat dari build. Pilih tim pengembangan Anda dan letakkan aplikasi di ponsel Anda! Anda mungkin ingin mengubah warna partikel dan skybox agar sesuai dengan kebutuhan Anda. Beri tahu saya di komentar jika Anda memiliki pertanyaan dan terima kasih telah mencari!