์ฑŒ๋ฆฐ์ง€

ํŒจ์ŠคํŠธ์บ ํผ์Šค ํ™˜๊ธ‰์ฑŒ๋ฆฐ์ง€ 3์ผ์ฐจ ๋ฏธ์…˜ (2์›” 3์ผ) : ์ดˆ๊ฒฉ์ฐจ ํŒจํ‚ค์ง€ : 21๊ฐœ ํ”„๋กœ์ ํŠธ๋กœ ์™„์„ฑํ•˜๋Š” ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์›น ๊ฐœ๋ฐœ with Three.js & Canvas ๊ฐ•์˜ ํ›„๊ธฐ

์–‘๋‚˜๋‹ˆ 2024. 2. 3. 14:12

์˜ค๋Š˜์€ ํŒŒํŠธ2 Canvas ๊ฐ•์˜์˜ ch1๊ณผ ch07์„ ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

๋“ฃ๋Š” ์ˆœ์„œ๋Š” ์ƒ๊ด€์—†๋‹ค๊ธฐ์— ใ…Žใ…Ž ๊ธฐ์ดˆ์ ์ธ ๊ฐ•์˜๋งŒ ๋“ฃ๊ณ  ๊ฐœ์ธ์ ์œผ๋กœ ์žฌ๋ฐŒ์–ด๋ณด์ด๋Š” ๊ฐ•์˜๋ถ€ํ„ฐ ๋“ค์—ˆ๋„ค์š”.

์บ”๋ฒ„์Šค๋„ ๋งค๋ฒˆ ์‚ฌ์šฉํ•  ๋•Œ๋งˆ๋‹ค ๊ฒ€์ƒ‰ํ•˜๋ฉด์„œ ์ผ๋˜ ๊ฒƒ ๊ฐ™์€๋ฐ ํ•œ ๋ฒˆ ๋”ฐ๋กœ ์ •๋ฆฌํ•ด ๋‘๋Š” ๊ฒŒ ์ข‹์„ ๊ฒƒ ๊ฐ™๋„ค์š”.

 

์ฑ•ํ„ฐ 01์—์„œ๋Š” ์บ”๋ฒ„์Šค ์‚ฌ์ด์ฆˆ์— ๋Œ€ํ•œ ๊ธฐ์ดˆ ์ง€์‹๋ถ€ํ„ฐ, ๊ธฐ๋ณธ ํŒŒํ‹ฐํด ๊ทธ๋ฆฌ๋Š” ๋ฐฉ๋ฒ• ๊ทธ๋ฆฌ๊ณ  ์ƒ์„ฑํ•œ ํŒŒํ‹ฐํด์— ๋‹ค์–‘ํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ ์šฉํ•ด ๋ณผ ์ˆ˜ ์žˆ์—ˆ๊ณ  ๋งˆ์ง€๋ง‰์—๋Š” ์บ”๋ฒ„์Šค resizeํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ๋„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d') // ๋“œ๋กœ์ž‰ ์ปจํƒ์ŠคํŠธ

// ์ฑ„์›Œ์ง„ ์‚ฌ๊ฐํ˜• ๊ทธ๋ฆฌ๊ธฐ (x, y, w, h)
ctx.fillRect(10,10,50,50)

// ์› ๊ทธ๋ฆฌ๊ธฐ
ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI/180*360) // ๊ฐ๋„๋Š” ๋ผ๋””์•ˆ ๋‹จ์œ„
ctx.fill() //์ฑ„์šฐ๊ธฐ. ์„ ์€ stroke()
ctx.closePath()

 

์บ”๋ฒ„์Šค์˜ ๋””ํดํŠธ ํฌ๊ธฐ๋Š” 300 * 150 px๋กœ ์„ค์ •๋˜์–ด ์žˆ๋‹ค. ์บ”๋ฒ„์Šค์˜ ์‚ฌ์ด์ฆˆ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ์‹์—๋Š” 2๊ฐ€์ง€๊ฐ€ ์žˆ๋Š”๋ฐ,

์ฒซ๋ฒˆ์จฐ ๋ฐฉ์‹์€ css๊ฐ’์„ ์ง์ ‘ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ด๊ณ  ๋‘๋ฒˆ์งธ๋Š” ์บ”๋ฒ„์Šค ์ž์ฒด width์™€ height๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

// css ์ˆ˜์ •
canvas.style.width = 300 + 'px'
canvas.style.height = 300 + 'px'

์ด ๋ฐฉ๋ฒ•์€ ์บ”๋ฒ„์Šค ๋†’์ด๋ฅผ ๊ฐ•์ œ๋กœ 2๋ฐฐ ๋Š˜๋ฆฌ๋Š”๊ฑฐ๋ผ ์บ”๋ฒ„์Šค์— ๊ทธ๋ฆฐ ์š”์†Œ์˜ ๋†’์ด๊ฐ€ ํ•จ๊ป˜ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋‹ค.

canvas.width = 300
canvas.height = 300

๊ทธ๋ ‡๊ธฐ์— ์œ„ ์ฝ”๋“œ์ฒ˜๋Ÿผ ์บ”๋ฒ„์Šค ๊ณ ์œ  ํฌ๊ธฐ๋„ ๊ฐ™์€ ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ค˜์•ผํ•œ๋‹ค.

html์ƒ์—์„œ ๋ณ€๊ฒฝํ• ๊ฑฐ๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ์†์„ฑ๊ฐ’์œผ๋กœ ์ค˜๋„ ๋œ๋‹ค.

<canvas id="canvas" width="300" height="300"></canvas>

 

DPR(Device Pixel Ratio)์— ๋Œ€ํ•ด์„œ๋„ ๊ฐ„๋‹จํžˆ ์–ธ๊ธ‰ํ•˜์…จ๋Š”๋ฐ, dpr=1์ธ ๋””์Šคํ”Œ๋ ˆ์ด์™€ 2์ธ ๋””์Šคํ”Œ๋ ˆ์ด(ex ๋ ˆํ‹ฐ๋‚˜ ๋””์Šคํ”Œ๋ ˆ์ด)์—์„œ 1ํ”ฝ์…€์„ ๊ทธ๋ฆฌ๋Š” ๊ฒŒ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ์ง€ ์•Œ๋ ค์ฃผ์…จ๋‹ค. DPR์ด ๋†’์„์ˆ˜๋ก ๋” ์„ ๋ช…ํ•œ ๊ทธ๋ž˜ํ”ฝ์„ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋Š” ์ด์œ ๋Š” ํ•˜๋‚˜์˜ CSS ํ”ฝ์…€์„ ์‹ค์ œ๋กœ ๊ทธ๋ฆฌ๋Š”๋ฐ 4๊ฐœ์˜ (๋ฌผ๋ฆฌ์ )ํ”ฝ์…€์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

* dpr : ์žฅ์น˜์˜ ๋ฌผ๋ฆฌ์  ํ”ฝ์…€๊ณผ CSS ํ”ฝ์…€์˜ ๋น„์œจ (๋ฌผ๋ฆฌ์  ํ”ฝ์…€/CSS ํ”ฝ์…€)

* dpr ๊ฐ’์€ window.devicePixelRatio๋กœ ํ™•์ธ ๊ฐ€๋Šฅ

์ด๋ฏธ์ง€ ์ถœ์ฒ˜: https://tomroth.com.au/dpr/DPR_viz.svg

 

requestAnimationFrame

์•„ ์ด๊ฒƒ๋„... ๋Š˜ ํ—ท๊ฐˆ๋ฆฌ๋Š” ๊ฐœ๋….. ๋”ฐ๋กœ ์ •๋ฆฌ๋ฅผ ํ•ด๋‘๋Š” ๊ฒŒ ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

์—ฌ๋Ÿฌ ํ”„๋ ˆ์ž„์ด ๋ชจ์—ฌ ํ•˜๋‚˜์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ๋˜๋Š” ์›๋ฆฌ๋ฅผ ๊ธฐ์–ต. x, y ์ขŒํ‘œ๋ฅผ ํ”„๋ ˆ์ž„๋งˆ๋‹ค ๋ณ€๊ฒฝํ•˜์—ฌ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋งŒ๋“ ๋‹ค. ์ด๋•Œ requestAnimationFrame์„ ์‚ฌ์šฉ. (setInterval ๋“ฑ์€ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ๋Š๊ธฐ๋Š” ๋А๋‚Œ์ด ๋‚จ)

function animate() {
    // animate ์‹คํ–‰ ํ›„ ๋‹ค์‹œ ์‹คํ–‰ (=๋งค ํ”„๋ ˆ์ž„๋งˆ๋‹ค ๊ณ„์† ์‹คํ–‰)
    window.requestAnimationFrame(animate)
    console.log(1)
}

1์ดˆ์— 60~ 240*๋ฒˆ์˜ ํ”„๋ ˆ์ž„์ด ์‹คํ–‰๋˜๊ณ  ๊ทธ๋•Œ๋งˆ๋‹ค ๋‚ด๋ถ€์— ์ž‘์„ฑํ•œ console.log๊ฐ€ ์‹คํ–‰๋จ.

* ๋ชจ๋‹ˆํ„ฐ ์ฃผ์‚ฌ์œจ์— ๋”ฐ๋ผ ๋‹ค๋ฆ„ (๋ณดํ†ต 60Hz ~ 144Hz)

๋ชจ๋‹ˆํ„ฐ ์ฃผ์‚ฌ์œจ์ด ๋ชจ๋‘ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋–ค ์‚ฌ๋žŒ์€ 1์ดˆ์— ๋‚ด๋ถ€ ์ฝ”๋“œ๊ฐ€ 144๋ฒˆ, ๋‹ค๋ฅธ ์‚ฌ๋žŒ์€ 60๋ฒˆ ์ด๋ ‡๊ฒŒ ๋‹ค๋ฅด๊ฒŒ ์‹คํ–‰๋  ์ˆ˜ ์žˆ์–ด์„œ delta ๊ฐ’์„ ์‚ฌ์šฉํ•ด์„œ ์ •๊ทœํ™”๋ฅผ ํ•ด์ค€๋‹ค.

FPS(Frame Per Second): ์ดˆ๋‹น ํ”„๋ ˆ์ž„ ํšŸ์ˆ˜. 1์ดˆ์— requestAnimationFrame์„ ๋ช‡ ๋ฒˆ ์‹คํ–‰ ์‹œํ‚ฌ๊นŒ

์˜ˆ๋ฅผ ๋“ค์–ด ๋‚ด ๋ชจ๋‹ˆํ„ฐ ์ฃผ์‚ฌ์œจ์ด 60hz ๋ผ๋Š” ๊ฒƒ์€ 1์ดˆ์— 60๋ฒˆ ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฒƒ์ด๊ณ  ์ด๋Š” ์•ฝ 16ms ๋งˆ๋‹ค requestAnimationFrame์ด ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฒƒ. ์ด๋•Œ FPS๋ฅผ 10์œผ๋กœ ๋‘”๋‹ค๋ฉด, 1์ดˆ์— 10๋ฒˆ ํ”„๋ ˆ์ž„์„ ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฒƒ์ด๊ณ  ๋‹ค๋ฅธ๋ง๋กœ๋Š” 100ms๋งˆ๋‹ค requestAnimationFrame์„ ์‹คํ–‰ํ•˜๋ผ๋Š” ์˜๋ฏธ!

 

delta ๊ฐ’์„ now - then ๊ฐ’์œผ๋กœ ๋‘๊ณ , delta ๊ฐ’์ด ๋ชฉํ‘œ Interval ๊ฐ’๋ณด๋‹ค ์ปค์งˆ ๋•Œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋™์ž‘!

์ด๋•Œ then ๊ฐ’์„ now - (delta % interval)๋กœ ๊ฐฑ์‹ ํ•ด์ค€๋‹ค. (100์œผ๋กœ ๋‚˜๋ˆˆ ๋‚˜๋จธ์ง€๊ฐ’์„ ๋นผ์คŒ์œผ๋กœ์จ then๊ฐ’์ด 1100, 1200, 1300.. ์œผ๋กœ ๊ฐฑ์‹ ๋จ)

 

SVG ํ•„ํ„ฐ ์ž…ํžˆ๊ธฐ

์ด๋ฏธ์ง€ ์ถœ์ฒ˜ : https://css-tricks.com/shape-blobbing-css/

 

Gooey ํšจ๊ณผ(์ ค๋ฆฌ์ฒ˜๋Ÿผ ์—ฐ๊ฒฐ๋˜๋Š”)์„ ๋‚ด๋ ค๋ฉด Blur & Contrast๋ฅผ ํ•จ๊ป˜ ์ž…ํžˆ๋ฉด ๋œ๋‹ค.

CSS๋กœ canvas์— ์ง์ ‘ ํšจ๊ณผ๋ฅผ ์ค„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ํˆฌ๋ช…ํ•œ ๋ฐฐ๊ฒฝ์—์„œ๋Š” ๋™์ž‘ํ•˜์ง€ ์•Š๊ณ  ๋ฐฐ๊ฒฝ์ƒ‰์ด ์žˆ์–ด์•ผ ๋™์ž‘ํ•ด์„œ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ์ƒ‰์ƒ์ด ์•„๋‹Œ, ๋Œ€๋น„๋˜๋Š” ์ƒ‰์ƒ์œผ๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

์ง€์˜ฅ์—์„œ ์˜ฌ๋ผ์˜จ ์Šฌ๋ผ์ž„

SVG ํ•„ํ„ฐ๊ฐ€ ์ค‘์ฒฉ๋˜๋Š” ๋ชจ์Šต์€ ์•„๋ž˜ ์‚ฌ์ดํŠธ์—์„œ๋„ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋‹ค.

https://yoksel.github.io/svg-filters/#/

์‹ค์ œ ์ž‘์—…๋ฌผ

* svg ํ•„ํ„ฐ ์ ์šฉํ•  ๋•Œ ๊ผญ ๋ฐฐ๊ฒฝ์ƒ‰์ƒ์€ ์ง€์›Œ์•ผํ•œ๋‹ค.. ใ… 

 

๊ทธ์™ธ์— dat.GUI์™€ resize ๋“ฑ์€ ์ƒ๋žต..

 

์บ”๋ฒ„์Šค๋ฅผ ๊ณต๋ถ€ํ•  ๋•Œ ๋งˆ๋‹ค ๋А๋ผ๋Š” ๊ฑฐ์ง€๋งŒ, ์€๊ทผ ์ˆ˜์‹์„ ๋งŽ์ด ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.. ๋จธ.. ์˜คํžˆ๋ ค ์žฌ๋ฐŒ์–ด! +v+)9 

๋จธ๋ฆฌ๋ฅผ ๋ง๋ž‘๋ง๋ž‘ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋ผ๋„ ์•ž์œผ๋กœ ์—ด์‹ฌํžˆ ๊ณต๋ถ€ํ•ด์•ผ๊ฒ ๋‹ค!

 

๋

 

์•„๋ž˜๋Š” ํ•™์Šต ์ธ์ฆ์ƒท!

 

๋ณธ ํฌ์ŠคํŒ…์€ ํŒจ์ŠคํŠธ์บ ํผ์Šค ํ™˜๊ธ‰ ์ฑŒ๋ฆฐ์ง€ ์ฐธ์—ฌ๋ฅผ ์œ„ํ•ด ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

https://fastcampus.co.kr/event_online_challenge_2401_mission

 

์ปค๋ฆฌ์–ด ์„ฑ์žฅ์„ ์œ„ํ•œ ์ตœ๊ณ ์˜ ์‹ค๋ฌด๊ต์œก ์•„์นด๋ฐ๋ฏธ | ํŒจ์ŠคํŠธ์บ ํผ์Šค

์„ฑ์ธ ๊ต์œก ์„œ๋น„์Šค ๊ธฐ์—…, ํŒจ์ŠคํŠธ์บ ํผ์Šค๋Š” ๊ฐœ์ธ๊ณผ ์กฐ์ง์˜ ์‹ค์งˆ์ ์ธ '์—…(ๆฅญ)'์˜ ์„ฑ์žฅ์„ ๋•๊ณ ์ž ๋ชจ๋“  ์ข…๋ฅ˜์˜ ๊ต์œก ์ฝ˜ํ…์ธ  ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋Œ€ํ•œ๋ฏผ๊ตญ No. 1 ๊ต์œก ์„œ๋น„์Šค ํšŒ์‚ฌ์ž…๋‹ˆ๋‹ค.

fastcampus.co.kr

https://bit.ly/48sS29N