Overworld Volumetric Cloud (preset "Volumetric" di CLOUD_QUALITY)

PERMINTAAN:
- Sumber teknik: kabut volumetrik The End (shaders/world1/lib/Volumetric_fog.glsl).
- Ketinggian slab: Y184 dasar, Y192 pusat, Y200 atas.
- Hanya 1 layer, ketebalan & kepadatan "diakali" (bukan raymarch) supaya sangat ringan.
- Refleksi awan 2D (dipakai di gbuffers_water.fsh) tidak boleh disentuh sama sekali.
- Preset baru "Volumetric" ditambahkan ke CLOUD_QUALITY (sebelumnya cuma Ultra
  Ringan/Detail Ringan). Saat dipilih: layer 2D lama jadi kabut tipis/buram di
  ketinggian (seolah awan yang lebih tinggi), digantikan awan volumetrik baru
  sebagai awan utama.
- Pengaturan ukuran/ketebalan awan volumetrik digabung ke settingan cloud yang
  sudah ada (screen.Atmospherics), bukan kategori terpisah.
- Tidak boleh dihaluskan pakai TAA -- pakai cara lain.

FILE YANG DIUBAH (semua di shaders/world0/, TIDAK ada file di luar world0
yang disentuh -- Nether & The End 100% tidak terpengaruh, sesuai
DIMENSION_INDEPENDENCE_NOTES.txt):

1. shaders/world0/lib/clouds.glsl
   - CLOUD_QUALITY sekarang [0 1 2], nilai 2 = Volumetric.
   - 2 setting baru digabung di blok setting cloud yang sudah ada:
     VLCLOUD_SCALE (ukuran gumpalan) dan CLOUD_VOLUMETRIC_2D_VEIL (seberapa
     kelihatan layer 2D lama saat mode Volumetric aktif).
   - const VLCLOUD_BASE_Y/CENTER_Y/TOP_Y = 184/192/200 (tetap, sesuai spek).
   - Fungsi baru (dibungkus "#if CLOUD_QUALITY == 2" -- nol biaya kalau
     preset lain dipilih, karena tidak ikut ter-compile sama sekali):
     - vlSmoothTex(): baca noise dengan interpolasi smoothstep manual (pola
       sama seperti smoothfilter() yang sudah ada di gbuffers_skybasic.fsh,
       ditulis ulang lokal karena urutan #include). Ini "opsi lain" pengganti
       TAA untuk menghaluskan tepi awan yang diminta.
     - vlCloudShape(): 2 tap noise (broad + 1 detail), bukan raymarch.
     - volumetricCloud(): 1 sample density di ketinggian pusat (Y192).
       Ketebalan slab (16 blok) "diakali" secara analitik lewat panjang
       lintasan ray menembus Y184-Y200 (VLCLOUD_THICKNESS/rayDir.y) -- makin
       landai arah pandang (dekat horizon) makin tebal/berkabut kelihatannya,
       tanpa perlu raymarch beneran. Pencahayaan pakai gaya yang sama dengan
       layer 2D (cloudCol, sunsetTint, top/underside light) supaya senada.
   - cloudShape()/cloud2D()/curvedCloudDistance() (fungsi layer 2D lama)
     TIDAK diubah satu baris pun.

2. shaders/world0/gbuffers_skybasic.fsh (render langit utama, BUKAN file
   refleksi air)
   - Di dalam blok "#ifdef CLOUDS": ditambah cabang
     "#if CLOUD_QUALITY == 2". Saat aktif: cloud2D() tetap dipanggil apa
     adanya (fungsinya sendiri tidak diubah), tapi hasilnya di-mix rendah
     (CLOUD_VOLUMETRIC_2D_VEIL) jadi veil tipis, lalu volumetricCloud()
     digambar di atasnya sebagai awan utama.
   - Selain blok itu, tidak ada baris lain yang diubah.

3. shaders/world0/gbuffers_water.fsh (refleksi awan di air) -- TIDAK DISENTUH
   SAMA SEKALI, sesuai permintaan. cloud2D() yang dipanggil di sini
   (baris ~312) tetap identik seperti sebelumnya.

4. shaders/shaders.properties (root, dipakai Overworld)
   - screen.Atmospherics: VLCLOUD_SCALE & CLOUD_VOLUMETRIC_2D_VEIL disisipkan
     tepat di sebelah CLOUD_QUALITY, tetap di layar/kategori "settingan
     cloud" yang sama, tidak bikin kategori baru.
   - sliders=: kedua setting baru didaftarkan juga supaya tampil sebagai
     slider, konsisten dengan CLOUD_* lain.

5. shaders/lang/en_US.lang & shaders/lang/id_ID.lang
   - Tambah value.CLOUD_QUALITY.2 = "Volumetric".
   - Tambah label untuk VLCLOUD_SCALE & CLOUD_VOLUMETRIC_2D_VEIL (EN & ID).

CATATAN PENGUJIAN:
- Kurung {}/() dan #if/#ifdef/#endif di ke-2 file yang diedit (clouds.glsl,
  gbuffers_skybasic.fsh) sudah dicek seimbang.
- Semua variabel yang dipakai fungsi baru (cameraPosition, frameTimeCounter,
  noisetex, sunVec, cloudCol, rainStrength) sudah dicek tersedia di KEDUA
  file yang meng-include clouds.glsl (gbuffers_skybasic.fsh DAN
  gbuffers_water.fsh) supaya tidak gagal compile di gbuffers_water.fsh
  walau fungsi barunya tidak dipanggil dari sana.
- Renderer Minecraft/Iris/OptiFine tidak tersedia di lingkungan ini, jadi
  hasil visual akhir (ukuran gumpalan, kepadatan, warna) tetap perlu dicek
  & di-tuning langsung di game lewat slider VLCLOUD_SCALE, CLOUD_COVERAGE,
  CLOUD_DENSITY, CLOUD_VOLUMETRIC_2D_VEIL, dst.

============================================================================
REVISI KE-2 (v500_1_2_VLCLOUD) -- feedback: kelihatan tipis di pinggir awan
============================================================================

PERMINTAAN:
- Waktu terbang naik & lihat ke arah pinggir/sisi awan, kelihatan tipis
  sekali -- minta pakai 4 tumpukan (layer) per gumpalan awan, bukan 1
  (mengganti instruksi "1 layer saja" sebelumnya).
- Saat terbang DI ATAS awannya, otomatis harus kelihatan seperti terbang
  di atas awan (dilihat dari atas).
- Tambah "logika warna dan arah cahaya": gradien hitam-putih ala pencahayaan
  bola, sisi menghadap matahari = putih (texture utama awan), sisi
  membelakangi = hitam (logika bayangan). Gradien ini harus ikut bergerak
  pelan mengikuti pergerakan matahari sepanjang hari (termasuk saat sore
  bergerak turun ke tengah horizon).

PERUBAHAN (semua di shaders/world0/, kecuali disebut lain):

1. shaders/world0/lib/clouds.glsl -- volumetricCloud() dirombak dari "1
   sample analitik + fake thickness" jadi RAYMARCH 4 LAYER SUNGGUHAN
   (VLCLOUD_LAYERS, #define, jangan diturunkan tanpa alasan kuat) menembus
   slab Y184-Y200 memakai akumulasi Beer-Lambert (transmittance/scattered),
   mirip pola kabut The End tapi jauh lebih ringan (4 layer, slab cuma 16
   blok, vs 8 layer sampai 140 blok). VLCLOUD_EXTINCTION (#define baru)
   mengatur seberapa cepat 4 layer ini menyerap cahaya -- perlu di-tuning
   di game.

2. vlIntersectSlab() (BARU, di clouds.glsl): cari rentang [tEntry,tExit]
   ray menembus slab Y184-Y200 pakai min/max dua bidang datar. Otomatis
   benar untuk kamera di bawah/di dalam/DI ATAS slab -- ini yang membuat
   pandangan "terbang di atas awan" otomatis muncul tanpa cabang if
   terpisah.

3. gbuffers_skybasic.fsh: panggilan volumetricCloud() DIPINDAH ke luar
   blok "if (fragpos.y > 0.)" (blok itu tetap ada, isinya cuma cloud2D
   veil/stars/sun seperti sebelumnya) -- supaya tetap dipanggil saat
   fragpos.y negatif (menunduk melihat awan dari atas). Tanpa perubahan
   ini, fitur "kelihatan dari atas" di volumetricCloud() tidak akan pernah
   ke-trigger walau logic slab-nya sudah benar.

4. Gradien "bola" mengikuti matahari (di clouds.glsl, di dalam loop
   raymarch):
   - cellLocal = fract(uv * skala broad) - 0.5 -> proxy posisi titik di
     dalam "sel" gumpalan awan (bukan normal 3D asli, cuma proxy 2D,
     disengaja biar tetap murah/tanpa sample tambahan).
   - sunPlanar = arah horizontal matahari (dari sunVec, dihitung ulang
     tiap frame -> ini yang bikin gradien "ikut bergerak" seiring waktu).
   - sphereGrad = dot(cellLocal, sunPlanar) diskalakan & di-clamp ke 0..1.
   - layerColor = mix(shadowColor [hitam/gelap], litColor [putih/terang],
     sphereGrad). gradientStrength lebih kontras saat matahari rendah
     (sunset/sunrise), lebih rata saat matahari tinggi (siang).
   - viewFromAbove (step(Y200, cameraPosition.y)) menambah sedikit extra
     brightness/whiteness ke shadowColor & litColor saat dilihat dari atas
     awan, supaya kesan "cloud sea" dari atas terasa beda dari dilihat
     dari bawah (murah: cuma step()+mix, tanpa texture tambahan).

5. vlDither()/vlHash() (BARU, lokal di clouds.glsl, BUKAN pakai nrand()
   dari lib/color_dither.glsl -- gbuffers_water.fsh yang juga meng-include
   clouds.glsl tidak meng-include color_dither.glsl, jadi kalau dipanggil
   dari sana bisa gagal compile). Dipakai buat geser titik awal raymarch
   antar 4 layer supaya tidak kelihatan berbaris/banding. Argumennya pakai
   gl_FragCoord.xy*texelSize (koordinat ternormalisasi 0..1), BUKAN pixel
   mentah, meniru pola nrand()/fp10Dither yang sudah ada supaya tidak kena
   masalah presisi sin() untuk argumen besar. Ini SATU FRAME SAJA, tidak
   ada buffer histori/reprojection sama sekali -- beda konsep total dari
   TAA, sesuai aturan "jangan gabung dengan TAA" yang masih berlaku.

KETERBATASAN "PANDANGAN DARI ATAS" DI REVISI KE-1 SUDAH TERATASI di revisi
ini lewat poin 2 & 3 di atas (vlIntersectSlab + pemanggilan di luar blok
fragpos.y>0).

CATATAN PERFORMA:
- 4 layer x 2 tap noise (vlCloudShape) = 8 baca texture per pixel awan,
  naik dari sebelumnya cuma 2 (1 sample). Ini pertukaran yang diminta
  sendiri (4 tumpukan) demi memperbaiki kesan tipis di pinggir awan.
  Kalau di game ternyata masih terlalu berat, titik pertama yang perlu
  diturunkan adalah VLCLOUD_LAYERS (4 -> 3) atau kurangi 1 tap noise di
  vlCloudShape().
- Belum ada testing render sungguhan (tidak ada Iris/OptiFine di
  lingkungan ini) -- ukuran gumpalan (VLCLOUD_SCALE), kontras gradien,
  dan warna tetap perlu di-tuning langsung di game.
- Kurung {}/() dan #if/#ifdef/#endif di ke-2 file yang diedit (clouds.glsl,
  gbuffers_skybasic.fsh) sudah dicek seimbang.
- Semua variabel yang dipakai fungsi baru (cameraPosition, frameTimeCounter,
  noisetex, sunVec, cloudCol, rainStrength) sudah dicek tersedia di KEDUA
  file yang meng-include clouds.glsl (gbuffers_skybasic.fsh DAN
  gbuffers_water.fsh) supaya tidak gagal compile di gbuffers_water.fsh
  walau fungsi barunya tidak dipanggil dari sana.
- Renderer Minecraft/Iris/OptiFine tidak tersedia di lingkungan ini, jadi
  hasil visual akhir (ukuran gumpalan, kepadatan, warna) tetap perlu dicek
  & di-tuning langsung di game lewat slider VLCLOUD_SCALE, CLOUD_COVERAGE,
  CLOUD_DENSITY, CLOUD_VOLUMETRIC_2D_VEIL, dst.

============================================================================
REVISI KE-3 -- feedback: hapus gradien warna, cukup bayangan di bawah awan
saja, & turunkan jumlah layer 4 -> 2
============================================================================

PERMINTAAN:
- Gradien "bola" hitam-putih mengikuti arah matahari (ditambah di revisi
  ke-2) DIHAPUS.
- Sebagai gantinya, cukup bayangan di BAGIAN BAWAH awan saja.
- VLCLOUD_LAYERS diturunkan dari 4 jadi 2.
- Selain itu tidak ada yang diubah (cloud2D()/refleksi air/setting lain
  tetap seperti semula).

PERUBAHAN (hanya di shaders/world0/lib/clouds.glsl, volumetricCloud()):

1. Blok "GRADIEN BOLA MENGIKUTI MATAHARI" dihapus total dari dalam loop
   raymarch: cellUV/cellLocal/faceSun/sphereGrad tidak dipakai lagi.
   Variabel pendukungnya yang cuma dipakai di situ (sunXZ, sunXZLen,
   sunPlanar, gradientStrength) ikut dihapus supaya tidak ada kode mati.
   sunDir/sunHeight/sunVisible/moonVisible/sunsetTint/moonFill/viewFromAbove
   TIDAK diubah -- masih dipakai untuk shadowColor/litColor seperti semula.

2. Pengganti (baru, di dalam loop yang sama):
   - heightInSlab = posisi tinggi sample raymarch saat ini di dalam slab
     Y184-Y200, dinormalisasi 0 (dasar) - 1 (atas).
   - underShadow = (1 - heightInSlab) * CLOUD_UNDERSIDE_DARKNESS -- makin
     dekat dasar awan, makin besar porsi shadowColor-nya.
   - layerColor = mix(litColor, shadowColor, underShadow).
   Pakai CLOUD_UNDERSIDE_DARKNESS yang SUDAH ADA (dipakai juga oleh
   cloud2D() untuk layer 2D lama) -- tidak menambah setting/slider baru,
   tidak menyentuh shaders.properties maupun file lang.
   Karena raymarch tetap menyapu dari tEntry ke tExit sesuai arah kamera
   (vlIntersectSlab yang menangani kamera di bawah/dalam/atas slab tidak
   diubah), sample yang paling dekat kamera (dan karena itu paling
   dominan lewat pembobotan transmittance) otomatis yang paling relevan
   dengan sudut pandang -- saat melihat dari bawah, sample dasar awan
   yang gelap itu yang paling kelihatan, jadi bayangannya konsisten
   terasa "di bawah awan" tanpa cabang if tambahan.

3. VLCLOUD_LAYERS: 4 -> 2 (satu baris #define). VLCLOUD_EXTINCTION,
   vlIntersectSlab(), vlCloudShape(), vlSmoothTex(), vlHash()/vlDither(),
   threshold/edgeWidth, opacity/transmittance, cloudPhaseBrightness, dan
   fungsi cloud2D() lama semuanya TIDAK disentuh.

4. Komentar dokumentasi di atas volumetricCloud() (blok "AWAN VOLUMETRIK
   OVERWORLD") diperbarui supaya tidak menyebut gradien bola atau angka
   "4 layer" lagi sebagai perilaku saat ini; histori revisi ke-1 & ke-2
   tetap disebutkan sebagai riwayat.

CATATAN PERFORMA:
- 2 layer x 2 tap noise (vlCloudShape) = 4 baca texture per pixel awan --
  turun dari 8 (revisi ke-2, 4 layer) dan masih lebih ringan dari kabut
  The End (8 layer, slab jauh lebih tebal).
- Menghapus gradien bola juga menghapus 1 baca texture tambahan per layer
  yang tadinya dipakai buat cellUV (perhitungan itu sebenarnya reuse
  variabel `uv` yang sudah ada, jadi ini bukan penghematan besar, tapi
  mengurangi jumlah instruksi ALU per sample).
- Belum ada testing render sungguhan (tidak ada Iris/OptiFine di
  lingkungan ini) -- kontras bayangan bawah (lewat slider
  CLOUD_UNDERSIDE_DARKNESS yang sudah ada) tetap perlu di-tuning langsung
  di game.
- Kurung {}/() dan #if/#ifdef/#endif di clouds.glsl sudah dicek seimbang
  ulang setelah edit ini (12/12 kurung kurawal, 234/234 kurung biasa,
  2/2 #if-#endif).
