ํจ์คํธ์บ ํผ์ค ํ๊ธ์ฑ๋ฆฐ์ง 3์ผ์ฐจ ๋ฏธ์ (2์ 3์ผ) : ์ด๊ฒฉ์ฐจ ํจํค์ง : 21๊ฐ ํ๋ก์ ํธ๋ก ์์ฑํ๋ ์ธํฐ๋ํฐ๋ธ ์น ๊ฐ๋ฐ with Three.js & Canvas ๊ฐ์ ํ๊ธฐ
์ค๋์ ํํธ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 ํํฐ ์ ํ๊ธฐ
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