From 6c3768e477d17df31250385a2b7a02a3f3fb1b09 Mon Sep 17 00:00:00 2001 From: sayudhalw Date: Thu, 27 Aug 2026 10:53:36 +0700 Subject: [PATCH] Refactor lighting and shadows in the scene - Removed pnpm-workspace.yaml configuration for esbuild. - Updated index.html title from "Lights" to "Shadows". - Enhanced script.js with new shadow textures and improved lighting setup: - Added ambient, directional, spot, and point lights with shadow capabilities. - Removed unused light configurations and helpers for clarity. - Introduced shadow casting and receiving for objects. - Updated sphere movement and shadow opacity based on position. - Added bakedShadow.jpg and simpleShadow.jpg texture files for shadow effects. --- pnpm-lock.yaml | 226 +++++++++++++++--------------- pnpm-workspace.yaml | 2 - src/index.html | 2 +- src/script.js | 230 ++++++++++++++----------------- static/textures/bakedShadow.jpg | Bin 0 -> 24487 bytes static/textures/simpleShadow.jpg | Bin 0 -> 11424 bytes 6 files changed, 214 insertions(+), 246 deletions(-) delete mode 100644 pnpm-workspace.yaml create mode 100644 static/textures/bakedShadow.jpg create mode 100644 static/textures/simpleShadow.jpg diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cf6fa10..b712aaa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -187,141 +187,141 @@ packages: os: [linux] libc: [glibc] - '@rollup/rollup-android-arm-eabi@4.62.5': - resolution: {integrity: sha512-jfkGfTwhQpsiSckPF8r9bU3pn3vyd72NlWaO+TgEO6WPSDnUhXzrNYCHBMOYj0ACaUgjm6eERLF+XV9a6RstoA==} + '@rollup/rollup-android-arm-eabi@4.63.0': + resolution: {integrity: sha512-70TeIFezKKy65LgAVyQh+w94/gjWhvPWaLaGGeMEgVrPkQhuj/M5bAYYZzIFUj9Y69oHyTm5Um/R6gcLh4A8JA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.62.5': - resolution: {integrity: sha512-oGVqyQlxnrz9/ty89oHpU857VUHEl5/Xu4R2lS+aivCTrNnSsbiENzTnNaBsjxH0CNWGPhzHArOLFwo+oKXveA==} + '@rollup/rollup-android-arm64@4.63.0': + resolution: {integrity: sha512-YC86tYIHK6M1IV+wbzO+Bxk8RCBr6ZyWYgWxUCzaZD8mc8rrFoIJDNzDrkHBYRc/wKdrsIXmm6/F7NzrAO+OrA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.62.5': - resolution: {integrity: sha512-bW7B8xMEq8n99Q3ieEcPRGuphurdZAaFzQc9Efyyw3FL6DZO6pMy9xhdN+kBoD7Sy05xNXSr4OyPPnpkYriS/A==} + '@rollup/rollup-darwin-arm64@4.63.0': + resolution: {integrity: sha512-oI+ECtUcli0y0fi4xpW82GdPIXdTkI8G8DSjG2LRuw09fPAGykaWYH/hXxiKuTxiAjiPSTIIuYUqof5Z2hShWw==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.62.5': - resolution: {integrity: sha512-YSwBS86QeHOGlrxJ1PSOIZSkzRL/JmKeunhc+lV6M1a6En8QuVCD/T/qIA0J4Gd2Y86RIOBYrLcOUtqGh9+/1w==} + '@rollup/rollup-darwin-x64@4.63.0': + resolution: {integrity: sha512-NwV+1s7TiKrMe4owHyKB/dTLD7ZJD0YEBEhIz+hvav1Cu1GReJjF+rsdNwjzENQeIAbE/CoNiaAc5Vz2h5DPAA==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.62.5': - resolution: {integrity: sha512-2fST8lILgl7cKbme/1KDdPCmbXbG+gqoV3bHp19L0ypX/3akYMBVdOunPleRCwonoLnXOZ/0F+Mt/v8POFmfcQ==} + '@rollup/rollup-freebsd-arm64@4.63.0': + resolution: {integrity: sha512-tWtHBTu5gOPK4u4Urtk4qAHW3zZ9rQAmbssO8gp7ELvGTGI3aCiq6NqyTQ0PCIg7KbHJF2UkGDDs77YZGxfjCA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.62.5': - resolution: {integrity: sha512-cpIxQCP9J+EVad0a6LO1kY3ZGODlk80VlI+2I96B8xMcdHZ4pLVhfQ49JFpYqjPF91FFkQWftf57YlDcTiw9yQ==} + '@rollup/rollup-freebsd-x64@4.63.0': + resolution: {integrity: sha512-2qPoJiwTvtHQ27NnYvTnsgk8laXWYuVmNESG8WFZBcEPKLfZ3I27qBJarjVRQtwGeYyRfq5ZowHXih9lm2BItw==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.62.5': - resolution: {integrity: sha512-r9fGh3eFs3e/udWh5ZjXQtxiYK/xoFxQaYR/cELxac/Udkl5Th+IsFm0CX3Kl9hmUH/we7EoMpjJgeQNnE0+IA==} + '@rollup/rollup-linux-arm-gnueabihf@4.63.0': + resolution: {integrity: sha512-FQwsTRvLNuHoTdICABJQfbPUSEueISGmnpT06tXTMpfprf5NiKLSXKA0A+w45wJnCmZAnzgqBwbt6ARFuyOi5w==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.62.5': - resolution: {integrity: sha512-xdvFdp7OM6KLJviJT2g/YuRSUjnZgGHk4RNgwIbN7X6cPugOucV60DdHXWzsBVCUdrGb6qSXnJQrrAKMmQuj3Q==} + '@rollup/rollup-linux-arm-musleabihf@4.63.0': + resolution: {integrity: sha512-BBVTXziw8mY1a4ZbWME9tZyfzqXCDPqaC7Z3heQ29p5dkvXzwL0NwelO8zLa8c3RBKvl3YTuSnBgsBhYBtwjIw==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.62.5': - resolution: {integrity: sha512-rRqILAndyzHzP7T9NFQrq+4HFWNhqkqkKur7eiBpfLmz01PO0JKx5Vchu3YllE4YXI/Ftgq/szrDWg5GJ0mI8g==} + '@rollup/rollup-linux-arm64-gnu@4.63.0': + resolution: {integrity: sha512-w2Iyy9+RqKwx3d9qWMKsJg0FfRBsY0/pXNv0mCQ3ueRvJI6+QAScfD4nrMlzFLs2HNVW6Ew+mtZfDl9b7Ew5/Q==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.62.5': - resolution: {integrity: sha512-Gf4X3qVMucayUvux6aXXPgXovocSFUC0rrffDuPI/S2nHhNMhjcZxsrAFYCOF350PRreW1XwzFj3CT/3bKsWCw==} + '@rollup/rollup-linux-arm64-musl@4.63.0': + resolution: {integrity: sha512-YK++KtrFRHYE0P6/RtYEAy9t8F37znP+K03RrIuLPYOL6SVlObRumf/0OE4V/h63xL9DwkWbNssZfmA9hawuDA==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.62.5': - resolution: {integrity: sha512-+s5qA0TNM0qm8PK/a5gt/1Hpx+NV08uSuCncvhziIlQzT6AEV2fnUQo7eBtFTFO0nA9scauvoR2HusfXmQnO4w==} + '@rollup/rollup-linux-loong64-gnu@4.63.0': + resolution: {integrity: sha512-aBfOG6fP7YkkPmTqPwufRJeFyz7WPpECv9XNbnsk9+vg7rxdih0lbtEel7jcRng4LZrrmU3FfitCFyEj4BWDWg==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.62.5': - resolution: {integrity: sha512-ybb6QvWwWJCbBWqERpc8K3pYVGIrXlG8MEQ8IIuJY6Y9KdHQxoFoNyfkAOtKn1VHu3KuLidXvwrvGR1mEjeWCw==} + '@rollup/rollup-linux-loong64-musl@4.63.0': + resolution: {integrity: sha512-LGaHEOeHNAag9VuS1Crs5DFg4RrU9MPi2nVnNJk9DTePx/B6RRYKVmrIXt2h7YOJlwjaFJ6lwtFDliZxScTLrQ==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.62.5': - resolution: {integrity: sha512-nZb1DtnOyhCmYvsC8A2CwOkopVg+IS1+fPUa7rMOAXtNw5+lLCLLPqd6XAiNrGtoQKsbvIBOwsHnBH/3wnb4HQ==} + '@rollup/rollup-linux-ppc64-gnu@4.63.0': + resolution: {integrity: sha512-jClvk+J0FC3b7Udvegiw5/4hErbHtmsNsQgENnKXDWtNCJXsJYZH5WURvu7imDOO38xYml24eeh5x3A04ppwCw==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.62.5': - resolution: {integrity: sha512-yMbj63Sp89ryrXLWyz+sy+fYD2HpOnMCLGbe4Oa1smclFSUukdtD/BgdiHaAetJNb74URD8U4hM+qG5KVzMEkg==} + '@rollup/rollup-linux-ppc64-musl@4.63.0': + resolution: {integrity: sha512-0OJlaGK+8+B777Ql5okIpD7ua5Ro9+VB9Ve0OKa28OQJZ1RbuUBVNHK/e3pr4BROqsyPl1JrPO1ZxJseCNffcA==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.62.5': - resolution: {integrity: sha512-mhoan3OJw2kYV/e1jtIdmvUZgyBFeA6zGWsOswmR0Tg19TQbowZuR+JMLID6spbbBN7Zee2ejrgmy3+FxGrIdA==} + '@rollup/rollup-linux-riscv64-gnu@4.63.0': + resolution: {integrity: sha512-Ygsx+HoNH7afwi1bTIXbnTvVnsO+zurPLSYxybV1hHFVU72OWOCl6v05ql/z0hkpAPx+DK7Kn9Bi7MayCcjLTA==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.62.5': - resolution: {integrity: sha512-5ZTLmjWbb1VZdjuyhe83K/8QO0/h11midQCBP+X5OYn32ra7eOBoM0ZqtaY4nkgNsYgmdVhMYPoyVPTjUpHf3w==} + '@rollup/rollup-linux-riscv64-musl@4.63.0': + resolution: {integrity: sha512-pDQxtMGb+OvG3fLwR2OkZlSd47hW+kWg4BYMG/++sR6RqorQccwPTDsxda5hPwiIeIErAnCF9ma3SAU06bdQtQ==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.62.5': - resolution: {integrity: sha512-m53kG+br6PGxOTmgBEM2DHSDs9RVjsyEbUwjJPJGTFm1grWOG8EKJggDCTb60unD4Tjby8fi7/m9XfkEWasVWg==} + '@rollup/rollup-linux-s390x-gnu@4.63.0': + resolution: {integrity: sha512-0BnUG9mS8I4SSHr3XsxVhuCMEiu+rX61xxZF5vujso4LaiAGFZFxvDjg6Xn6tLPNTUAfuCvQYas4LMQMVsKRSQ==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.62.5': - resolution: {integrity: sha512-6RHPJR1g/uvdYU8uXBnfq3nlqyZCP82Fr6NHgfGoaIeSh0YEqnX/x6uA9MmJJbnSH7swqX4F+CkGdUF+6doiQA==} + '@rollup/rollup-linux-x64-gnu@4.63.0': + resolution: {integrity: sha512-Adu/VttB1dpPNW+FEacrZ+xVm9tFty84+RrFzsqlFaPxoJB+9XXyDGtp5dCOoBwGBIEVH0To7lExFXEx0BIF4A==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.62.5': - resolution: {integrity: sha512-xs+OXQtEXgpXT0DmA5+U3qnRZHdCST/5HRQxS8wSPZTUZN/EMWeHuSIod32LQklTBZBV9DyfncKBQ8n5V3eFdw==} + '@rollup/rollup-linux-x64-musl@4.63.0': + resolution: {integrity: sha512-NQ3bDvjUbFKmP23671xUlXtKmqVsUBd6M4PQCvbmNtOy06hnQIdKHy8oG/6S3R/S6He1JgPk6A5VT+prAJMYEw==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.62.5': - resolution: {integrity: sha512-e7hD+sl3s+mcLQDZ8pbudBVsdG6r5yN4w3LqG2TJ8sQHDpblWj5lrJs/3m01Cvlxbt4x13zu5thLjgypgtkYzw==} + '@rollup/rollup-openbsd-x64@4.63.0': + resolution: {integrity: sha512-u2eDAl4+0aFvA13GxlGBtTI3SS3sdgwgtV0HyjZ0QaQVCgNE+jqNGey+GtxWiq+wxr/UycAx/OnfJzApCFamvA==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.62.5': - resolution: {integrity: sha512-GiyJaCf+WpMub/17aPcKk27QMl5W6f+KhdPTjlFOn5akH5Wa/DCM9Stdx5cDfmasyKB08MqpVQ1uJE2RkkpbXg==} + '@rollup/rollup-openharmony-arm64@4.63.0': + resolution: {integrity: sha512-XvRb5vfW3wAZQ+ZUG21AnHHDKtNcw99eigzEhjr//NZ3u7SoBaPP0seSc7FgP7p1epAEdAoZckMW9WY/+4w70w==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.62.5': - resolution: {integrity: sha512-+OQ8U2DdoEfXl8T4Fb18AjmEwbXMerKDKCL8yCPAYhKCEEKoul7rkbeGCBFCbAlaGaa7pmtRTpkAJM2LE/i5FA==} + '@rollup/rollup-win32-arm64-msvc@4.63.0': + resolution: {integrity: sha512-iZPmniy4kNBf5yo2RezbkYNNK5HPbXE9+g+twnbqSng7dtLEJy1SKoxiE/ni4FDacjyuZpEeb9U054N4EoKHYw==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.62.5': - resolution: {integrity: sha512-KanvAZrPKbDBFwrgiU9yEVpQoox9QPV1WZOXX7HudJQY+eSlu82CtWxDU8WtuRRvtN5EGkLczkd6Y6DTcvm9wA==} + '@rollup/rollup-win32-ia32-msvc@4.63.0': + resolution: {integrity: sha512-mFBBd+LF37fnE8JnYUOH+imj0aPFPK30vpar4ehJkgnLj9sZn8ZxiRENmLtgIwxK7TC8klF6N57fxdNBwQoqOA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.62.5': - resolution: {integrity: sha512-1aC3UEWTtRl3RK3VpDJ/Tqk1XI4SLTmXIthAq6wRWo8XiSXJNd+VprJM4/1P4+i6HIaFEFlVi9sTTziniD2tOQ==} + '@rollup/rollup-win32-x64-gnu@4.63.0': + resolution: {integrity: sha512-ujeqEY3B+zbGn3Z4Q03cUBG/LGWnBJncVT36WER31LcOsQk9+1dmINKKtvmmfChUvRbK1G0R8OhMWFgHgaZtAw==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.62.5': - resolution: {integrity: sha512-/gDJaRs4gl0NPIwqCz+6PkpmhhjRAD2j6P4rSNHBzUkO3naEx2mIU0pRle1vUNRQ7mE/+8OOeXLTv/J56FKiQg==} + '@rollup/rollup-win32-x64-msvc@4.63.0': + resolution: {integrity: sha512-hncn90N4sOky0L2LKE5oESKLbxCPeVo4eLA2LSMoDzM+879ml4WSr+Rr4DWknNIVVvS1Hirkc9hx02W6YxS8rQ==} cpu: [x64] os: [win32] @@ -378,16 +378,16 @@ packages: resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} - picomatch@4.0.5: - resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} engines: {node: '>=12'} postcss@8.5.26: resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==} engines: {node: ^10 || ^12 || >=14} - rollup@4.62.5: - resolution: {integrity: sha512-/tqMfgP7GPA3PHhCmuiS4vIjrSVhHLgY++i+dhbG462euyAj7FpM4D9uq1X3BgjlqRdpcOrYhcQtfiQLNc8tqw==} + rollup@4.63.0: + resolution: {integrity: sha512-T5vnZ2y4QqC3/4P+w2+JO+Q/OVdnPsv4XcSYJYMEn0R9/jjl5AgLwO9LAZMzP2lN71O6pypn91rB7lDstUkfrQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -534,79 +534,79 @@ snapshots: '@napi-rs/lzma-linux-x64-gnu@1.5.1': optional: true - '@rollup/rollup-android-arm-eabi@4.62.5': + '@rollup/rollup-android-arm-eabi@4.63.0': optional: true - '@rollup/rollup-android-arm64@4.62.5': + '@rollup/rollup-android-arm64@4.63.0': optional: true - '@rollup/rollup-darwin-arm64@4.62.5': + '@rollup/rollup-darwin-arm64@4.63.0': optional: true - '@rollup/rollup-darwin-x64@4.62.5': + '@rollup/rollup-darwin-x64@4.63.0': optional: true - '@rollup/rollup-freebsd-arm64@4.62.5': + '@rollup/rollup-freebsd-arm64@4.63.0': optional: true - '@rollup/rollup-freebsd-x64@4.62.5': + '@rollup/rollup-freebsd-x64@4.63.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.62.5': + '@rollup/rollup-linux-arm-gnueabihf@4.63.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.62.5': + '@rollup/rollup-linux-arm-musleabihf@4.63.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.62.5': + '@rollup/rollup-linux-arm64-gnu@4.63.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.62.5': + '@rollup/rollup-linux-arm64-musl@4.63.0': optional: true - '@rollup/rollup-linux-loong64-gnu@4.62.5': + '@rollup/rollup-linux-loong64-gnu@4.63.0': optional: true - '@rollup/rollup-linux-loong64-musl@4.62.5': + '@rollup/rollup-linux-loong64-musl@4.63.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.62.5': + '@rollup/rollup-linux-ppc64-gnu@4.63.0': optional: true - '@rollup/rollup-linux-ppc64-musl@4.62.5': + '@rollup/rollup-linux-ppc64-musl@4.63.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.62.5': + '@rollup/rollup-linux-riscv64-gnu@4.63.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.62.5': + '@rollup/rollup-linux-riscv64-musl@4.63.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.62.5': + '@rollup/rollup-linux-s390x-gnu@4.63.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.62.5': + '@rollup/rollup-linux-x64-gnu@4.63.0': optional: true - '@rollup/rollup-linux-x64-musl@4.62.5': + '@rollup/rollup-linux-x64-musl@4.63.0': optional: true - '@rollup/rollup-openbsd-x64@4.62.5': + '@rollup/rollup-openbsd-x64@4.63.0': optional: true - '@rollup/rollup-openharmony-arm64@4.62.5': + '@rollup/rollup-openharmony-arm64@4.63.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.62.5': + '@rollup/rollup-win32-arm64-msvc@4.63.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.62.5': + '@rollup/rollup-win32-ia32-msvc@4.63.0': optional: true - '@rollup/rollup-win32-x64-gnu@4.62.5': + '@rollup/rollup-win32-x64-gnu@4.63.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.62.5': + '@rollup/rollup-win32-x64-msvc@4.63.0': optional: true '@types/estree@1.0.9': {} @@ -644,9 +644,9 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 - fdir@6.5.0(picomatch@4.0.5): + fdir@6.5.0(picomatch@4.0.7): optionalDependencies: - picomatch: 4.0.5 + picomatch: 4.0.7 fill-range@7.1.1: dependencies: @@ -670,7 +670,7 @@ snapshots: picomatch@2.3.2: {} - picomatch@4.0.5: {} + picomatch@4.0.7: {} postcss@8.5.26: dependencies: @@ -678,36 +678,36 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - rollup@4.62.5: + rollup@4.63.0: dependencies: '@types/estree': 1.0.9 optionalDependencies: '@napi-rs/lzma-linux-x64-gnu': 1.5.1 - '@rollup/rollup-android-arm-eabi': 4.62.5 - '@rollup/rollup-android-arm64': 4.62.5 - '@rollup/rollup-darwin-arm64': 4.62.5 - '@rollup/rollup-darwin-x64': 4.62.5 - '@rollup/rollup-freebsd-arm64': 4.62.5 - '@rollup/rollup-freebsd-x64': 4.62.5 - '@rollup/rollup-linux-arm-gnueabihf': 4.62.5 - '@rollup/rollup-linux-arm-musleabihf': 4.62.5 - '@rollup/rollup-linux-arm64-gnu': 4.62.5 - '@rollup/rollup-linux-arm64-musl': 4.62.5 - '@rollup/rollup-linux-loong64-gnu': 4.62.5 - '@rollup/rollup-linux-loong64-musl': 4.62.5 - '@rollup/rollup-linux-ppc64-gnu': 4.62.5 - '@rollup/rollup-linux-ppc64-musl': 4.62.5 - '@rollup/rollup-linux-riscv64-gnu': 4.62.5 - '@rollup/rollup-linux-riscv64-musl': 4.62.5 - '@rollup/rollup-linux-s390x-gnu': 4.62.5 - '@rollup/rollup-linux-x64-gnu': 4.62.5 - '@rollup/rollup-linux-x64-musl': 4.62.5 - '@rollup/rollup-openbsd-x64': 4.62.5 - '@rollup/rollup-openharmony-arm64': 4.62.5 - '@rollup/rollup-win32-arm64-msvc': 4.62.5 - '@rollup/rollup-win32-ia32-msvc': 4.62.5 - '@rollup/rollup-win32-x64-gnu': 4.62.5 - '@rollup/rollup-win32-x64-msvc': 4.62.5 + '@rollup/rollup-android-arm-eabi': 4.63.0 + '@rollup/rollup-android-arm64': 4.63.0 + '@rollup/rollup-darwin-arm64': 4.63.0 + '@rollup/rollup-darwin-x64': 4.63.0 + '@rollup/rollup-freebsd-arm64': 4.63.0 + '@rollup/rollup-freebsd-x64': 4.63.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.63.0 + '@rollup/rollup-linux-arm-musleabihf': 4.63.0 + '@rollup/rollup-linux-arm64-gnu': 4.63.0 + '@rollup/rollup-linux-arm64-musl': 4.63.0 + '@rollup/rollup-linux-loong64-gnu': 4.63.0 + '@rollup/rollup-linux-loong64-musl': 4.63.0 + '@rollup/rollup-linux-ppc64-gnu': 4.63.0 + '@rollup/rollup-linux-ppc64-musl': 4.63.0 + '@rollup/rollup-linux-riscv64-gnu': 4.63.0 + '@rollup/rollup-linux-riscv64-musl': 4.63.0 + '@rollup/rollup-linux-s390x-gnu': 4.63.0 + '@rollup/rollup-linux-x64-gnu': 4.63.0 + '@rollup/rollup-linux-x64-musl': 4.63.0 + '@rollup/rollup-openbsd-x64': 4.63.0 + '@rollup/rollup-openharmony-arm64': 4.63.0 + '@rollup/rollup-win32-arm64-msvc': 4.63.0 + '@rollup/rollup-win32-ia32-msvc': 4.63.0 + '@rollup/rollup-win32-x64-gnu': 4.63.0 + '@rollup/rollup-win32-x64-msvc': 4.63.0 fsevents: 2.3.3 source-map-js@1.2.1: {} @@ -716,8 +716,8 @@ snapshots: tinyglobby@0.2.17: dependencies: - fdir: 6.5.0(picomatch@4.0.5) - picomatch: 4.0.5 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 to-regex-range@5.0.1: dependencies: @@ -731,10 +731,10 @@ snapshots: vite@6.4.3: dependencies: esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.5) - picomatch: 4.0.5 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 postcss: 8.5.26 - rollup: 4.62.5 + rollup: 4.63.0 tinyglobby: 0.2.17 optionalDependencies: fsevents: 2.3.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml deleted file mode 100644 index 5ed0b5a..0000000 --- a/pnpm-workspace.yaml +++ /dev/null @@ -1,2 +0,0 @@ -allowBuilds: - esbuild: true diff --git a/src/index.html b/src/index.html index 78c1635..38d1de7 100644 --- a/src/index.html +++ b/src/index.html @@ -3,7 +3,7 @@ - Lights + Shadows diff --git a/src/script.js b/src/script.js index 18d73f1..f22ba1b 100644 --- a/src/script.js +++ b/src/script.js @@ -1,8 +1,17 @@ import * as THREE from 'three'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; -import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js'; import GUI from 'lil-gui'; + +/** + * Textures + */ +const textureLoader = new THREE.TextureLoader(); +const bakedShadow = textureLoader.load('/textures/bakedShadow.jpg'); +bakedShadow.colorSpace = THREE.SRGBColorSpace; +const simpleShadow = textureLoader.load('/textures/simpleShadow.jpg'); +simpleShadow.colorSpace = THREE.SRGBColorSpace; + /** * Base */ @@ -18,154 +27,111 @@ const scene = new THREE.Scene(); /** * Lights */ -const ambientLight = new THREE.AmbientLight(); -ambientLight.color = new THREE.Color(0xffffff); -ambientLight.intensity = 1; +// Ambient light +const ambientLight = new THREE.AmbientLight(0xffffff, .4); +gui.add(ambientLight, 'intensity').min(0).max(3).step(0.001); scene.add(ambientLight); -const ambientLightFolder = gui.addFolder('Ambient Light').close(); -ambientLightFolder.add(ambientLight, 'intensity').min(0).max(3).step(0.001).name('Ambient Light Intensity'); -//------------------------------------------------------------------------------ -const directionalLight = new THREE.DirectionalLight(); -directionalLight.color = new THREE.Color(0x00fffc); -directionalLight.intensity = 0.9; -directionalLight.position.set(1, .25, 0); +// Directional light +const directionalLight = new THREE.DirectionalLight(0xffffff, .4); +directionalLight.position.set(2, 2, - 1); +gui.add(directionalLight, 'intensity').min(0).max(3).step(0.001); +gui.add(directionalLight.position, 'x').min(- 5).max(5).step(0.001); +gui.add(directionalLight.position, 'y').min(- 5).max(5).step(0.001); +gui.add(directionalLight.position, 'z').min(- 5).max(5).step(0.001); scene.add(directionalLight); -const directionalLightFolder = gui.addFolder('Directional Light').close(); -directionalLightFolder.add(directionalLight, 'intensity').min(0).max(3).step(0.001).name('Directional Light Intensity'); -directionalLightFolder.add(directionalLight.position, 'x').min(-5).max(5).step(0.001).name('Directional Light X'); -directionalLightFolder.add(directionalLight.position, 'y').min(-5).max(5).step(0.001).name('Directional Light Y'); -directionalLightFolder.add(directionalLight.position, 'z').min(-5).max(5).step(0.001).name('Directional Light Z'); +directionalLight.castShadow = true; +directionalLight.shadow.mapSize.width = 1024; +directionalLight.shadow.mapSize.height = 1024; +directionalLight.shadow.camera.top = 2; +directionalLight.shadow.camera.right = 2; +directionalLight.shadow.camera.bottom = - 2; +directionalLight.shadow.camera.left = - 2; +directionalLight.shadow.camera.near = 1; +directionalLight.shadow.camera.far = 6; +directionalLight.shadow.radius = 10; -//Helper -const directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight, 0.2); -scene.add(directionalLightHelper); -//------------------------------------------------------------------------------ -const hemisphereLight = new THREE.HemisphereLight(); -hemisphereLight.color = new THREE.Color(0xff0000); -hemisphereLight.groundColor = new THREE.Color(0x0000ff); -hemisphereLight.intensity = 0.9; -scene.add(hemisphereLight); +const directionalLightCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera); +directionalLightCameraHelper.visible = false; +scene.add(directionalLightCameraHelper); -const hemisphereLightFolder = gui.addFolder('Hemisphere Light').close(); -hemisphereLightFolder.add(hemisphereLight, 'intensity').min(0).max(3).step(0.001).name('Hemisphere Light Intensity'); -hemisphereLightFolder.addColor(hemisphereLight, 'color').name('Hemisphere Light Color'); -hemisphereLightFolder.addColor(hemisphereLight, 'groundColor').name('Hemisphere Light Ground Color'); +// Spot light +const spotLight = new THREE.SpotLight(0xffffff, 3.6, 10, Math.PI * 0.3); +spotLight.castShadow = true; +spotLight.shadow.mapSize.width = 1024; +spotLight.shadow.mapSize.height = 1024; +spotLight.shadow.camera.fov = 30; +spotLight.shadow.camera.near = 1; +spotLight.shadow.camera.far = 6; +spotLight.shadow.radius = 10; +spotLight.position.set(0, 2, 2); +scene.add(spotLight); +scene.add(spotLight.target); -//Helper -const hemisphereLightHelper = new THREE.HemisphereLightHelper(hemisphereLight, 0.2); -scene.add(hemisphereLightHelper); -//------------------------------------------------------------------------------ -const pointLight = new THREE.PointLight(); -pointLight.color = new THREE.Color(0xff9000); -pointLight.distance = 10; -pointLight.decay = 2; -pointLight.intensity = 1.5; -pointLight.position.set(1, -0.5, 1); +const spotLightCameraHelper = new THREE.CameraHelper(spotLight.shadow.camera); +spotLightCameraHelper.visible = false; +scene.add(spotLightCameraHelper); + +// Point Light +const pointLight = new THREE.PointLight(0xffffff, 2.7); +pointLight.castShadow = true; +pointLight.shadow.mapSize.width = 1024; +pointLight.shadow.mapSize.height = 1024; +pointLight.shadow.camera.near = 0.1; +pointLight.shadow.camera.far = 5; +pointLight.position.set(-1, 1, 0); scene.add(pointLight); -const pointLightFolder = gui.addFolder('Point Light').close(); -pointLightFolder.addColor(pointLight, 'color').name('Point Light Color'); -pointLightFolder.add(pointLight, 'distance').min(0).max(20).step(0.001).name('Point Light Distance'); -pointLightFolder.add(pointLight, 'decay').min(0).max(5).step(0.001).name('Point Light Decay'); -pointLightFolder.add(pointLight, 'intensity').min(0).max(3).step(0.001).name('Point Light Intensity'); -pointLightFolder.add(pointLight.position, 'x').min(-5).max(5).step(0.001).name('Point Light X'); -pointLightFolder.add(pointLight.position, 'y').min(-5).max(5).step(0.001).name('Point Light Y'); -pointLightFolder.add(pointLight.position, 'z').min(-5).max(5).step(0.001).name('Point Light Z'); +const pointLightCameraHelper = new THREE.CameraHelper(pointLight.shadow.camera); +pointLightCameraHelper.visible = false; +scene.add(pointLightCameraHelper); -//helper -const pointLightHelper = new THREE.PointLightHelper(pointLight, 0.2); -scene.add(pointLightHelper); -//------------------------------------------------------------------------------ -const rectAreaLight = new THREE.RectAreaLight(); -rectAreaLight.color = new THREE.Color(0x4e00ff); -rectAreaLight.intensity = 6; -rectAreaLight.width = 1; -rectAreaLight.height = 1; -rectAreaLight.position.set(-1.5, 0, 1.5); -rectAreaLight.lookAt(new THREE.Vector3(0, 0, 0)); -scene.add(rectAreaLight); +/** + * Materials + */ +const material = new THREE.MeshStandardMaterial(); +material.roughness = 0.7; +gui.add(material, 'metalness').min(0).max(1).step(0.001); +gui.add(material, 'roughness').min(0).max(1).step(0.001); -const rectAreaLightFolder = gui.addFolder('Rect Area Light').close(); -rectAreaLightFolder.addColor(rectAreaLight, 'color').name('Color'); -rectAreaLightFolder.add(rectAreaLight, 'intensity').min(0).max(10).step(0.001).name('Intensity'); -rectAreaLightFolder.add(rectAreaLight, 'width').min(0).max(20).step(0.001).name('Width'); -rectAreaLightFolder.add(rectAreaLight, 'height').min(0).max(20).step(0.001).name('Height'); -rectAreaLightFolder.add(rectAreaLight.position, 'x').min(-5).max(5).step(0.001).name('X'); -rectAreaLightFolder.add(rectAreaLight.position, 'y').min(-5).max(5).step(0.001).name('Y'); -rectAreaLightFolder.add(rectAreaLight.position, 'z').min(-5).max(5).step(0.001).name('Z'); - -//helper -const rectAreaLightHelper = new RectAreaLightHelper(rectAreaLight); -scene.add(rectAreaLightHelper); -//------------------------------------------------------------------------------ -const spotLight = new THREE.SpotLight(); -spotLight.color = new THREE.Color(0x78ff00); -spotLight.intensity = 0.5; -spotLight.distance = 10; -spotLight.angle = Math.PI * 0.1; -spotLight.penumbra = 0.25; -spotLight.decay = 1; -spotLight.position.set(0, 2, 3); -scene.add(spotLight); - -const spotLightFolder = gui.addFolder('Spot Light').close(); -spotLightFolder.addColor(spotLight, 'color').name('Color'); -spotLightFolder.add(spotLight, 'intensity').min(0).max(10).step(0.001).name('Intensity'); -spotLightFolder.add(spotLight, 'distance').min(0).max(20).step(0.001).name('Distance'); -spotLightFolder.add(spotLight, 'angle').min(0).max(Math.PI * 2).step(0.001).name('Angle'); -spotLightFolder.add(spotLight, 'penumbra').min(0).max(1).step(0.001).name('Penumbra'); -spotLightFolder.add(spotLight, 'decay').min(0).max(5).step(0.001).name('Decay'); -spotLightFolder.add(spotLight.position, 'x').min(-5).max(5).step(0.001).name('X'); -spotLightFolder.add(spotLight.position, 'y').min(-5).max(5).step(0.001).name('Y'); -spotLightFolder.add(spotLight.position, 'z').min(-5).max(5).step(0.001).name('Z'); - -//helper -const spotLightHelper = new THREE.SpotLightHelper(spotLight); -scene.add(spotLightHelper); -window.requestAnimationFrame(() => -{ - spotLightHelper.update(); -}); -//------------------------------------------------------------------------------ /** * Objects */ -// Material -const material = new THREE.MeshStandardMaterial(); -material.roughness = 0.4; - -// Objects const sphere = new THREE.Mesh( new THREE.SphereGeometry(0.5, 32, 32), material ); -sphere.position.x = - 1.5; - -const cube = new THREE.Mesh( - new THREE.BoxGeometry(0.75, 0.75, 0.75), - material -); - -const torus = new THREE.Mesh( - new THREE.TorusGeometry(0.3, 0.2, 32, 64), - material -); -torus.position.x = 1.5; +sphere.castShadow = true; const plane = new THREE.Mesh( new THREE.PlaneGeometry(5, 5), + // new THREE.MeshStandardMaterial({ + // map: bakedShadow + // }) material ); plane.rotation.x = - Math.PI * 0.5; -plane.position.y = - 0.65; +plane.position.y = - 0.5; +plane.receiveShadow = true; -scene.add(sphere, cube, torus, plane); +scene.add(sphere, plane); + +const sphereShadow = new THREE.Mesh( + new THREE.PlaneGeometry(1.5, 1.5), + new THREE.MeshBasicMaterial({ + color: 0x000000, + transparent: true, + alphaMap: simpleShadow + }) +); +sphereShadow.rotation.x = - Math.PI * 0.5; +sphereShadow.position.y = plane.position.y + .01; +scene.add(sphereShadow); /** - * Sizes - */ +* Sizes +*/ const sizes = { width: window.innerWidth, height: window.innerHeight @@ -209,8 +175,11 @@ const renderer = new THREE.WebGLRenderer({ renderer.setSize(sizes.width, sizes.height); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); +renderer.shadowMap.enabled = false; +renderer.shadowMap.type = THREE.PCFSoftShadowMap; + /** - * Animate +* Animate */ const clock = new THREE.Clock(); @@ -218,14 +187,15 @@ const tick = () => { const elapsedTime = clock.getElapsedTime(); - // Update objects - sphere.rotation.y = 0.1 * elapsedTime; - cube.rotation.y = 0.1 * elapsedTime; - torus.rotation.y = 0.1 * elapsedTime; + // Update Sphere + sphere.position.x = Math.cos(elapsedTime) * 1.5; + sphere.position.z = Math.sin(elapsedTime) * 1.5; + sphere.position.y = Math.abs(Math.sin(elapsedTime) * 3); - sphere.rotation.x = 0.15 * elapsedTime; - cube.rotation.x = 0.15 * elapsedTime; - torus.rotation.x = 0.15 * elapsedTime; + // Update Shadow + sphereShadow.position.x = sphere.position.x; + sphereShadow.position.z = sphere.position.z; + sphereShadow.material.opacity = (1 - sphere.position.y) * .3; // Update controls controls.update(); diff --git a/static/textures/bakedShadow.jpg b/static/textures/bakedShadow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0119ea17a3ca642af7dc473161be77019498c4d5 GIT binary patch literal 24487 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 literal 0 HcmV?d00001 diff --git a/static/textures/simpleShadow.jpg b/static/textures/simpleShadow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..641aaf9c2824aa3aba1bb011ac986bb162c03c54 GIT binary patch literal 11424 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 literal 0 HcmV?d00001