ํ™ˆ three.js shadow ์‚ดํŽด๋ณด๊ธฐ
ํฌ์ŠคํŠธ
์ทจ์†Œ

three.js shadow ์‚ดํŽด๋ณด๊ธฐ

๐Ÿ’ป ๊ทธ๋ฆผ์ž๋ฅผ ๋งŒ๋“œ๋Š” ์›๋ฆฌ

three.js ์—์„œ๋Š” ๊ทธ๋ฆผ์ž๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด Shadow Map ์„ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค.
Shadow Map ์ด๋ž€ ๊ทธ๋ฆผ์ž ์ •๋ณด๋ฅผ ์ €์žฅํ•  texture ๋ฅผ ์˜๋ฏธํ•˜๋ฉฐ, ๋งŒ๋“ค์–ด์ง€๋Š” ๊ณผ์ •๊ณผ ์ด๋ฅผ ์ด์šฉํ•ด ๊ทธ๋ฆผ์ž๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. scene ์„ ๋ Œ๋”๋งํ•˜๊ธฐ ์ง์ „์—, light ์˜ ์‹œ์ ์—์„œ ๋ Œ๋”๋ง์„ ๋จผ์ € ํ•ฉ๋‹ˆ๋‹ค.

  2. ์ด๋•Œ, mesh ๋“ค์˜ material ์€ MeshDepthMaterial ๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.

  3. Light ์˜ ์‹œ์ ์—์„œ ๋ Œ๋”๋ง๋œ scene ์€ Shadow Map ์ด๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” texture ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

  4. ๋งŒ๋“ค์–ด์ง„ Shadow Map ๋“ค์„ ์ข…ํ•ฉํ•ด ์ตœ์ข… scene ์„ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.

20๊ฐœ์˜ mesh ์™€ 5๊ฐœ์˜ light ๋“ค์ด ์žˆ๋‹ค๋ฉด, ์ด 6๋ฒˆ ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. 5๊ฐœ์˜ light ์‹œ์ ์—์„œ ํ•œ๋ฒˆ์”ฉ, ์ด ๊ณผ์ •์—์„œ ๋‚˜์˜จ Shadow Map ๋“ค์„ ํ•ฉ์ณ ์ตœ์ข…์ ์œผ๋กœ ํ•œ๋ฒˆ ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
๋งŒ์•ฝ ์กฐ๋ช…ํ•˜๋‚˜๋ฅผ ๋” ์ถ”๊ฐ€ํ•œ๋‹ค๋ฉด, 7๋ฒˆ ๋ Œ๋”๋ง ํ›„์— ์ตœ์ข… ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ light ๋ณ„๋กœ ๋งŒ๋“ค์–ด์ง„ Shadow Map ์„ ์‹œ๊ฐํ™”ํ•œ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.
shadow_map_viewer

๐Ÿ’ป ๊ทธ๋ฆผ์ž ๋งŒ๋“ค๊ธฐ

๊ทธ๋ฆผ์ž๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋จผ์ € renderer ์˜ shadowMap ์„ ํ™œ์„ฑํ™” ์‹œ์ผœ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

1
renderer.shadowMap.enabled = true;

๋˜ํ•œ Object3D ๊ฐ€ ๊ทธ๋ฆผ์ž๋ฅผ ๋งŒ๋“œ๋Š”์ง€(Shadow Map ์ƒ์„ฑ), ๋งŒ๋“ค์–ด์ง„ ๊ทธ๋ฆผ์ž๊ฐ€ ๋งฝํžˆ๋Š”์ง€์— ๋”ฐ๋ผ castShadow ์™€ receiveShadow ์˜ต์…˜์„ ํ™œ์„ฑํ™” ์‹œ์ผœ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

1
2
mesh1.castShadow = true;
mesh2.receiveShadow = true;

์ถ”๊ฐ€๋กœ ์•ž์„œ ์‚ดํŽด๋ณธ ์กฐ๋ช…๋“ค์ค‘ DirectionalLight, SpotLight, PointLight ๋งŒ ๊ทธ๋ฆผ์ž๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ‘จโ€๐Ÿ’ป DirectionalLight

1
2
3
4
5
6
7
8
9
10
11
12
// ...์ƒ๋žต...
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.castShadow = true;
// ...์ƒ๋žต...
planeMesh.receiveShadow = true;

cubeMesh.castShadow = true;
cubeMesh.receiveShadow = true;

sphereMesh.castShadow = true;
sphereMesh.receiveShadow = true;
// ...์ƒ๋žต...

์œ„ ์ฝ”๋“œ๋Š” DirectionalLight ๋ฅผ ์ด์šฉํ•˜์—ฌ Mesh ์— ๊ทธ๋ฆผ์ž๋“ค์„ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.
๊ทธ๋ฆผ์ž๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ ์กฐ๋ช…์— castShadow ์˜ต์…˜์„ ํ™œ์„ฑํ™” ํ•ด์ค€๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๊ทธ๋ฆผ์ž๊ฐ€ ๋งฝํž planeMesh ์—๋Š” receiveShadow ์˜ต์…˜์„, ๊ทธ๋ฆผ์ž๊ฐ€ ์ƒ์„ฑ๋  cubeMesh ์™€ sphereMesh ์—๋Š” receiveShadow ์˜ต์…˜์„ ํ™œ์„ฑํ™” ํ–ˆ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜๋Š” ์œ„์ฝ”๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚จ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค.

directional-light-shadow-1

๐Ÿ–Š ๊ทธ๋ฆผ์ž ์ตœ์ ํ™”ํ•˜๊ธฐ

์กฐ๋ช…์— ์˜ํ•ด ๋งŒ๋“ค์–ด์ง„ ๊ทธ๋ฆผ์ž๋Š” ์ƒํ™ฉ์— ๋”ฐ๋ผ ์ตœ์ ํ™”๋ฅผ ํ•ด์•ผํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
์œ„ ๊ฒฐ๊ณผ์—์„œ๋„ ๊ทธ๋ฆผ์ž๊ฐ€ ์ž˜๋ ค ์ƒ์„ฑ๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์•„๋ž˜์—์„œ ์‚ดํŽด๋ณผ ์š”์†Œ๋ฅผ ๋”ฐ๋ผ ์ตœ์ ํ™”๋ฅผ ์‹œ์ผœ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • camera
    Shadow Map ์„ ๋งŒ๋“ค๋•Œ light ์˜ ์‹œ์ ์—์„œ ๋ Œ๋”๋ง์„ ์ง„ํ–‰ํ•˜๋Š”๋ฐ, ์ด๋•Œ light ์˜ camera ๋ฅผ ์ด์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด camera ๋Š” scene ์„ ๋ Œ๋”๋งํ•˜๋Š” camera ์™€ ๊ฐ™์€ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ CameraHelper ๋กœ ์‹œ๊ฐํ™” ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ทธ ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    directional-light-shadow-2 ์œ„ ๊ฒฐ๊ณผ๋ฅผ ํ†ตํ•ด, DirectionalLight ์˜ camera ๋Š” OrthographicCamera ์ž„์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    camera ๋ฅผ ํ†ตํ•ด ์ตœ์ ํ™” ํ•  ์ˆ˜ ์žˆ๋Š” ์š”์†Œ๋Š” ๋ Œ๋”๋ง ๋ฒ”์œ„ ์ž…๋‹ˆ๋‹ค. ๋ Œ๋”๋ง ๋ฒ”์œ„๊ฐ€ ์ž‘์•„์งˆ ์ˆ˜๋ก, ๊ทธ๋ฆผ์ž๋Š” ์ •๊ตํ•ด์ง€์ง€๋งŒ, ๋„ˆ๋ฌด ์ž‘์•„์ง€๋ฉด ๊ทธ๋ฆผ์ž๊ฐ€ ์ž˜๋ฆฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
    ์œ„ ์ด๋ฏธ์ง€์—์„œ๋Š” ํ›„์ž์— ํ•ด๋‹นํ•˜๋‹ˆ ๋ฒ”์œ„๋ฅผ ๋„“ํ˜€๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

    1
    2
    3
    4
    5
    6
    
    // ...์ƒ๋žต...
    directionalLight.shadow.camera.top = 3;
    directionalLight.shadow.camera.bottom = -8;
    directionalLight.shadow.camera.left = -7;
    directionalLight.shadow.camera.right = 7;
    // ...์ƒ๋žต...3
    

    directional-light-shadow-3

    ์ถ”๊ฐ€๋กœ near, far ๋„ ๋ฒ”์œ„์— ๋งž๊ฒŒ ์กฐ์ ˆํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

    1
    2
    3
    4
    
    // ...์ƒ๋žต...
    directionalLight.shadow.camera.near = 1;
    directionalLight.shadow.camera.far = 15;
    // ...์ƒ๋žต...
    

    directional-light-shadow-4

  • Render Size
    Shadow Map ์€ ์ผ์ข…์˜ texture ๋กœ, ํฌ๊ธฐ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    ๊ฐ’์ด ํด์ˆ˜๋ก, ๊ทธ๋ฆผ์ž๊ฐ€ ์ •๊ตํ•ด์ง€์ง€๋งŒ, ์—ฐ์‚ฐ๋Ÿ‰์ด ๋งŽ์•„์ ธ ์„ฑ๋Šฅ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๊ฐ’์€ mipmap ์ƒ์„ฑ์„ ์œ„ํ•ด 2 ์˜ ๊ฑฐ๋“ญ์ œ๊ณฑ์œผ๋กœ ์„ค์ •ํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    1
    2
    3
    4
    
    // ...์ƒ๋žต...
    directionalLight.shadow.mapSize.width = 1024;
    directionalLight.shadow.mapSize.height = 1024;
    // ...์ƒ๋žต...
    
  • Shadow Map Type

    ํƒ€์ž…ํŠน์ง•
    BasicShadowMap์„ฑ๋Šฅ์€ ์ข‹์ง€๋งŒ, ํ’ˆ์งˆ์ด ๋‚ฎ์Šต๋‹ˆ๋‹ค.
    PCFShadowMap๊ธฐ๋ณธ๊ฐ’์œผ๋กœ, ๋ถ€๋“œ๋Ÿฌ์šด ํ…Œ๋‘๋ฆฌ๋ฅผ ๊ฐ€์ง„ ๊ทธ๋ฆผ์ž๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์ง€๋งŒ ์„ฑ๋Šฅ์€ ์กฐ๊ธˆ ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.
    PCFSoftShadowMap๋ถ€๋“œ๋Ÿฌ์šด ๊ทธ๋ฆผ์ž๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ,
    ํŠนํžˆ ์ € ํ•ด์ƒ๋„์˜ Shadow Map ์ผ ๋•Œ, ๋”์šฑ ๋ถ€๋“œ๋Ÿฌ์›Œ ์ง‘๋‹ˆ๋‹ค. ์„ฑ๋Šฅ์€ ๋‚ฎ์Šต๋‹ˆ๋‹ค.
    VSMShadowMapํ•ด๋‹น ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด,
    receiveShadow ๊ฐ€ ํ™œ์„ฑํ™”๋œ ๊ฐ์ฒด๋“ค์€ castShadow ์˜ต์…˜์„ ํ™œ์„ฑํ™” ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.
  • blur
    radius ์†์„ฑ์„ ํ†ตํ•ด ๊ทธ๋ฆผ์ž ํ…Œ๋‘๋ฆฌ์— ํ๋ฆฐ(blur) ํšจ๊ณผ๋ฅผ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    ๊ฐ’์ด 1 ๋ณด๋‹ค ํฌ๋ฉด ํšจ๊ณผ๊ฐ€ ์ ์šฉ๋˜๋ฉฐ, Shadow Map ์˜ type ์ด PCFSoftShadowMap ๋‚˜ BasicShadowMap ์ผ ๊ฒฝ์šฐ๋Š” ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

    1
    2
    3
    
    // ...์ƒ๋žต...
    directionalLight.shadow.radius = 10;
    // ...์ƒ๋žต...
    

    directional-light-shadow-5

๐Ÿ‘จโ€๐Ÿ’ป SpotLight

1
2
3
4
// ...์ƒ๋žต...
const spotLight = new THREE.SpotLight(0xffffff, 1);
spotLight.castShadow = true;
// ...์ƒ๋žต...

์œ„ ์ฝ”๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ SpotLight ์— ๊ทธ๋ฆผ์ž๋ฅผ ์ƒ์„ฑํ•œ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

spot-light-shadow-1

๐Ÿ–Š ๊ทธ๋ฆผ์ž ์ตœ์ ํ™”ํ•˜๊ธฐ

๊ทธ๋ฆผ์ž๋ฅผ ์ตœ์ ํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ DirectionalLight ์™€ ๊ฑฐ์˜ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค.
์ด ๋ถ€๋ถ„์—์„œ๋Š” ๋‹ค๋ฅธ์ ์„ ์œ„์ฃผ๋กœ ์„œ์ˆ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

  • camera
    SpotLight ๋Š” ๊ทธ๋ฆผ์ž๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด PerspectiveCamera ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. CameraHelper ๋ฅผ ํ†ตํ•ด ์‹œ๊ฐํ™”ํ•œ ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    spot-light-shadow-2

    SpotLight ์˜ camera ์˜ fov ๋Š” angle ๊ณผ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์œผ๋ฉฐ, aspect ๋Š” Shadow Map ์˜ ํฌ๊ธฐ์— ๋”ฐ๋ผ ์ž๋™์œผ๋กœ ์ •ํ•ด์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ near ์™€ far ๋ฅผ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ‘จโ€๐Ÿ’ป PointLight

1
2
3
4
// ...์ƒ๋žต...
const pointLight = new THREE.PointLight(0xffffff, 1);
pointLight.castShadow = true;
// ...์ƒ๋žต...

์œ„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

point-light-shadow-1

๐Ÿ–Š ๊ทธ๋ฆผ์ž ์ตœ์ ํ™”ํ•˜๊ธฐ

  • camera
    PointLight ๋Š” ๊ทธ๋ฆผ์ž๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด PerspectiveCamera ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    PointLight camera ์˜ near ์™€ far ์†์„ฑ์„ ์กฐ์ •ํ•ด ๋ Œ๋”๋ง ๋ฒ”์œ„๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    point-light-shadow-3

    SpotLight ์™€ ๊ฐ™์€ camera ๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ์ฐจ์ด์ ์€ PointLight ๋Š” ๋ชจ๋“  ๋ฐฉํ–ฅ์œผ๋กœ ๋น›์„ ๋ฐœ์‚ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ •์œก๋ฉด์ฒด์˜ ๊ฐ๋ฉด์— ์กฐ๋ช…์„ ๋†“์€๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ฆ‰ PointLight ๋Š” ์ •์œก๋ฉด์ฒด ๊ฐ ๋ฐฉํ–ฅ์œผ๋กœ 6๋ฒˆ์„ ๋ Œ๋”๋งํ•ด์•ผ ํ•จ์œผ๋กœ ๋‹ค๋ฅธ ์กฐ๋ช…๋ณด๋‹ค ์„ฑ๋Šฅ์ด ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.

๐Ÿ’ป ๊ฐ€์งœ ๊ทธ๋ฆผ์ž ๋งŒ๋“ค๊ธฐ

์œ„์—์„œ ์‚ดํŽด๋ณด์•˜๋“ฏ์ด, ๊ทธ๋ฆผ์ž๋ฅผ ๋งŒ๋“œ๋Š” ๊ณผ์ •์€ ๊นŒ๋‹ค๋กญ๊ณ  ๋น„์šฉ๋„ ํฝ๋‹ˆ๋‹ค.
๊ทธ๋ฆผ์ž ํ˜•ํƒœ์˜ texture ๋ฅผ ์ด์šฉํ•˜๋ฉด, ๋ณต์žกํ•œ ์—ฐ์‚ฐ ์—†์ด๋„ ๊ทธ๋ฆผ์ž๊ฐ€ ์ƒ๊ธฐ๋Š” ํšจ๊ณผ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น texture ๋ฅผ ์ž…ํžŒ PlaneGeometry ๋ฅผ ๊ทธ๋ฆผ์ž๊ฐ€ ์ƒ๊ฒจ์•ผํ•˜๋Š” ์œ„์น˜์— ๋‘๋ฉด ๋ฉ๋‹ˆ๋‹ค.

fake-shadow

์œ„ texture ๋ฅผ ์ด์šฉํ•ด์„œ ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ...์ƒ๋žต...

// Fake Shadow
const fakeShadowGeometry = new THREE.PlaneGeometry(6, 6);
const fakeShadowMaterial = new THREE.MeshBasicMaterial({
  alphaMap: fakeShadowTexture,
  transparent: true,
  color: 0x000000,
});

const fakeShadow = new THREE.Mesh(fakeShadowGeometry, fakeShadowMaterial);

fakeShadow.position.set(0, 0.01, 0);
fakeShadow.rotation.set(-(Math.PI * 0.5), 0, 0);
// ...์ƒ๋žต...

์œ„ ์ฝ”๋“œ๋Š” PlaneGeometry ์— ๊ทธ๋ฆผ์ž texture ๋ฅผ ์ ์šฉ์‹œํ‚จ ํ›„, ์‹œ๊ณ„๋ฐฉํ–ฅ์œผ๋กœ ํšŒ์ „์‹œํ‚ค๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.
y ์ถ•์„ 0 ๋ณด๋‹ค ๋ฏธ์„ธํ•˜๊ฒŒ ํฌ๊ฒŒ ์„ค์ •ํ•ด์ค€ ์ด์œ ๋Š”, z-fighting ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์œ„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚จ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

fake-shadow-2 Sphere ๋ถ€๋ถ„์˜ ๊ทธ๋ฆผ์ž๊ฐ€ ์ƒ๊ฒผ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ฐฉ์‹์˜ ๋ฌธ์ œ์ ์€, ๊ทธ๋ฆผ์ž๊ฐ€ ์›€์ง์ด์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. Light ์— ์˜ํ•œ ๊ทธ๋ฆผ์ž๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— mesh ๊ฐ€ ์›€์ง์—ฌ๋„ ๊ทธ๋ฆผ์ž๋Š” ์›๋ž˜์˜ ์ž๋ฆฌ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, mesh ์˜ ๊ฑฐ๋ฆฌ์™€ ์ƒ๊ด€์—†์ด ํ•ญ์ƒ ๊ฐ™์€ ๊ทธ๋ฆผ์ž๊ฐ€ ๋‚˜์˜ต๋‹ˆ๋‹ค.

๋จผ์ € mesh ๊ฐ€ ์ง€๋ฉด์—์„œ ๋ฉ€์–ด์ง์— ๋”ฐ๋ผ, ๊ทธ๋ฆผ์ž๊ฐ€ ๋‹ค๋ฅด๊ฒŒ ๋ Œ๋”๋ง ๋  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ...์ƒ๋žต...
const animation = () => {
  const elapsedTime = clock.getElapsedTime();

  sphere.position.y = Math.abs(Math.sin(elapsedTime * 3) * 5) + 3;
  fakeShadow.material.opacity = 1 - sphere.position.y * 0.05;

  renderer.render(scene, camera);

  requestAnimationFrame(animation);
};

requestAnimationFrame(animation);
// ...์ƒ๋žต...

Sphere ๊ฐ€ ๋ฉ€์–ด์ง์— ๋”ฐ๋ผ(y ์ขŒํ‘œ๊ฐ€ ์ปค์ง์— ๋”ฐ๋ผ), ๊ทธ๋ฆผ์ž์˜ ํˆฌ๋ช…๋„๋Š” 0 ์— ๊ฐ€๊นŒ์›Œ์ ธ์•ผ ํ•จ์œผ๋กœ 1 ์—์„œ ๋นผ์ค€๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์œ„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚จ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

fake-shadow-3

๋‹ค์Œ์œผ๋กœ Mesh ์˜ ์›€์ง์ž„๊ณผ ๊ทธ๋ฆผ์ž texture ๋ฅผ ์ ์šฉํ•œ Mesh ๊ฐ„์˜ ์œ„์น˜๋ฅผ ๋™๊ธฐํ™” ์‹œ์ผœ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// ...์ƒ๋žต...
const animation = () => {
  const elapsedTime = clock.getElapsedTime();

  sphere.position.x = Math.sin(elapsedTime * 5);
  sphere.position.z = Math.cos(elapsedTime * 5);
  sphere.position.y = Math.abs(Math.sin(elapsedTime * 3) * 5) + 3;

  fakeShadow.position.x = sphere.position.x;
  fakeShadow.position.z = sphere.position.z;
  fakeShadow.material.opacity = 1 - sphere.position.y * 0.05;

  renderer.render(scene, camera);

  requestAnimationFrame(animation);
};

requestAnimationFrame(animation);
// ...์ƒ๋žต...

Sphere ์˜ ์›์šด๋™์— ์˜ํ•ด ๋ฐ”๋€ ์ขŒํ‘œ๋ฅผ, ๊ทธ๋ฆผ์ž texture ๊ฐ€ ์ ์šฉ๋œ mesh ์— ์ ์šฉํ•ด ์คŒ์œผ๋กœ์จ ๋‘ mesh ์‚ฌ์ด์˜ ์œ„์น˜๋ฅผ ๋™๊ธฐํ™” ํ•ด์ฃผ๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.
๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

fake-shadow-4

๐Ÿ“— ์ฐธ๊ณ ์ž๋ฃŒ

Shadows

์ด ๊ธฐ์‚ฌ๋Š” ์ €์ž‘๊ถŒ์ž์˜ CC BY 4.0 ๋ผ์ด์„ผ์Šค๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

three.js light ์‚ดํŽด๋ณด๊ธฐ

three.js ์™ธ๋ถ€ ๋ชจ๋ธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ