
WebGL์์ GLSL ์ ฐ์ด๋ ์์ค ์ฝ๋๋ฅผ ์ ์ํ ๋ JavaScript ๋ด๋ถ์ ๋ฃ์ง ์๊ณ ๋ณ๋์ ํ์ผ๋ก ๋นผ๊ณ ์ฐ๊ฒฐํ๋ ๊ฒ์ด ๊ด๋ฆฌํ๊ธฐ์ ์ข์ต๋๋ค. ๋๊ฐ ์ด๋ ๊ฒ ํ์ผ์ ๋ง๋ค๊ณ ์ด ์์ GLSL ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค. shaders ํด๋ ์์ ๋ฃ์ผ๋ฉด ์ข๊ฒ ๋ค์.
vertex.glslfragment.glsl์ด๋ ๊ฒ ๋ณ๋ ํ์ผ์ ๋ง๋ค๋ฉด ์๋ํฐ์์ Syntax Highlighting์ด ๋๊ณ ์ฌ์ฌ์ฉ์ด ๊ฐ๋ฅํ ์ฅ์ ์ด ์์ต๋๋ค. ํ์ง๋ง ์ด ๋ฐฉ์์ผ๋ก ์ฝ๋๋ฅผ ์์ฑํ ๋๋ ๋ธ๋ผ์ฐ์ ์ ๋ณด์ ์ ์ฑ ์ ๋ฐ๋ผ JS์์ ๋ก์ปฌ ํ์ผ(์ฌ๊ธฐ์๋ .glsl ํ์ผ)์ ์ง์ ์ฝ์ ์ ์๋ค๋ ๊ฒ์ ์ฃผ์ํด์ผ ํฉ๋๋ค.
fecth() API๋ฅผ ์ฌ์ฉํ์ฌ ์๋ฒ๋ก๋ถํฐ ํ
์คํธ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ณผ์ ์ด ํ์ํ๊ณ , ์ด ํ
์คํธ๋ฅผ ๋ถ๋ฌ์ค๋ ๋์ ๊ธฐ๋ค๋ ค์ผ ํ๋ฏ๋ก async/await ๊ฐ์ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ด ํ์ํฉ๋๋ค.
๋ธ๋ผ์ฐ์ ํ๊ฒฝ์ ์ฌ์ฉ์์ ์ปดํจํฐ์ ์๋ ๋ก์ปฌ ํ์ผ ์์คํ ์ ๋ํ ์ง์ ์ ์ธ ์ ๊ทผ์ ์๊ฒฉํ ์ฐจ๋จํฉ๋๋ค. ๋ง์ฝ ์น์ฌ์ดํธ์ ๋ฐฉ๋ฌธํ์ ๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์๋ฌด๋ฐ ์ ์ฝ ์์ด ๋ก์ปฌ ํ์ผ์ ์ฝ์ ์ ์๋ค๋ฉด, ์ ์ฑ ์ฌ์ดํธ๊ฐ ์ฌ์ฉ์์ ๋น๋ฐ๋ฒํธ ํ์ผ์ด๋ ๊ฐ์ธ ๋ฌธ์๋ฅผ ๋ชฐ๋ ํ์ณ๊ฐ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋ธ๋ผ์ฐ์ ๋ '๋์ผ ์ถ์ฒ ์ ์ฑ
'์ ๋ฐ๋ฆ
๋๋ค. ์ฆ, ์น ํ์ด์ง๊ฐ ์คํ ์ค์ธ ์๋ฒ(์: http://localhost:8080)์ ๋ฆฌ์์ค๋ฅผ ์์ฒญํ๋ ์๋ฒ์ ์ฃผ์๊ฐ ์ผ์นํด์ผ ํฉ๋๋ค. ๋ก์ปฌ ํ์ผ ๊ฒฝ๋ก(file:///C:/...)๋ HTTP ํ๋กํ ์ฝ์ด ์๋๊ธฐ ๋๋ฌธ์ ์น ํ์ค ๋ณด์ ๊ท์ ์ ์ง์ ์ ์ธ JS ์ ๊ทผ์ด ๊ฑฐ๋ถ๋ฉ๋๋ค.
fetch()๋ HTTP/HTTPS ํ๋กํ ์ฝ์ ํตํด ์๋ฒ์ "์ด ํ์ผ์ ์ฃผ์ธ์"๋ผ๊ณ ์ ์์ผ๋ก ์์ฒญ์ ๋ณด๋ด๋ ์ธํฐํ์ด์ค์
๋๋ค. ์ด๋ ๋ง์น ํธ์ง๋ฅผ ์จ์ ์ฐ์ฒด๊ตญ(๋ธ๋ผ์ฐ์ )์ ํตํด ์๋๋ฐฉ(์๋ฒ)์๊ฒ ์ ๋ฌํ๊ณ ๋ต์ฅ์ ๋ฐ๋ ๊ณผ์ ๊ณผ ๊ฐ์ต๋๋ค. ๋ก์ปฌ์์ ๊ฐ๋ฐ ์ค์ด๋ผ๋ฉด, ๋จ์ํ ํ์ผ ์ด๊ธฐ๊ฐ ์๋๋ผ ๋ก์ปฌ ์น ์๋ฒ(Live Server, Python http.server ๋ฑ)๋ฅผ ์คํํ์ฌ ํ์ผ์ '์ฃผ์(URL)'๋ฅผ ๋ถ์ฌํด์ผ๋ง fetch()๋ก ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
๋คํธ์ํฌ๋ฅผ ํตํด ํ์ผ์ ๊ฐ์ ธ์ค๋ ๊ณผ์ ์ CPU์ ์ฐ์ฐ ์๋์ ๋นํด ๋งค์ฐ ๋๋ฆฐ ์์ ์ ๋๋ค. ๋ง์ฝ ๋ธ๋ผ์ฐ์ ๊ฐ ํ์ผ์ ๊ฐ์ ธ์ฌ ๋๊น์ง ์๋ฌด๊ฒ๋ ๋ชป ํ๊ณ ๋ฉ์ถฐ ์๋ค๋ฉด, ์ฌ์ฉ์๋ ํ๋ฉด์ด ์ผ์ด๋ถ์ ๊ฒ์ฒ๋ผ ๋๋ผ๊ฒ ๋ฉ๋๋ค. ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด ์์ ์ ๊ธฐ๋ค๋ฆฌ๋ ๋์ ๋ธ๋ผ์ฐ์ ์ ๋ฉ์ธ ์ค๋ ๋๊ฐ ๋ฉ์ถ์ง ์๊ณ ๋ค๋ฅธ ์์ (๋ ๋๋ง, ์ด๋ฒคํธ ์ฒ๋ฆฌ ๋ฑ)์ ๊ณ์ํ ์ ์๊ฒ ๋ฉ๋๋ค.
fetch()๊ฐ ํธ์ถ๋๋ฉด ์ฆ์ ๊ฒฐ๊ณผ๊ฐ์ ์ฃผ๋ ๋์ , "๋ฏธ๋์ ๋ฐ์ดํฐ๋ฅผ ์ค๊ฒ"๋ผ๋ Promise๋ผ๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค. ์ด ๊ฐ์ฒด๋ ํ์ฌ ์ธ ๊ฐ์ง ์ํ๋ฅผ ๊ฐ์ง๋๋ค: Pending(๋๊ธฐ), Fulfilled(์ดํ/์ฑ๊ณต), Rejected(๊ฑฐ๋ถ/์คํจ).
Promise๋ฅผ ๋ ์ง๊ด์ ์ผ๋ก ๋ค๋ฃจ๊ธฐ ์ํ ๋ฌธ๋ฒ์ ๋๋ค.
async: ํด๋น ํจ์๊ฐ ๋น๋๊ธฐ์ ์ผ๋ก ์๋ํ ๊ฒ์์ ์ ์ธํฉ๋๋ค. ์ด ํจ์๋ ํญ์ Promise๋ฅผ ๋ฐํํฉ๋๋ค.
await: Promise๊ฐ ํด๊ฒฐ(Fulfilled)๋ ๋๊น์ง ํจ์์ ์คํ์ ์ ์ '์ผ์ ์ ์ง' ์ํต๋๋ค. ํ์ง๋ง ์ ์ฒด ๋ธ๋ผ์ฐ์ ๋ฅผ ๋ฉ์ถ๋ ๊ฒ์ด ์๋๋ผ, ํด๋น ํจ์ ๋ด๋ถ์ ํ๋ฆ๋ง ๊ธฐ๋ค๋ฆฌ๋ ๊ฒ์ด๋ฏ๋ก ๋ค๋ฅธ UI ์ ๋๋ฉ์ด์
์ด๋ ์ด๋ฒคํธ๋ ์ ์ ์๋ํฉ๋๋ค.
์
ฐ์ด๋ ํ์ผ์ fetch()๋ก ๋ถ๋ฌ์ ๋ฌธ์์ด๋ก ๋ณํํ๋ ๊ธฐ๋ณธ ์ฝ๋์
๋๋ค.
/**
* @description ์ธ๋ถ ์
ฐ์ด๋ ํ์ผ์ ๋น๋๊ธฐ์ ์ผ๋ก ๋ก๋ํ๋ ํจ์
* @param {string} url - ์
ฐ์ด๋ ํ์ผ์ ๊ฒฝ๋ก (URL)
* @returns {Promise<string>} - ์
ฐ์ด๋ ์์ค ์ฝ๋ ๋ฌธ์์ด
*/
async function loadShaderSource(url) {
try {
// 1. fetch()๋ฅผ ํตํด ์๋ฒ์ ๋ฆฌ์์ค ์์ฒญ (๋น๋๊ธฐ ๋๊ธฐ)
const response = await fetch(url);
// 2. ์๋ต์ด ์ฑ๊ณต์ (status 200-299)์ธ์ง ํ์ธ
if (!response.ok) {
throw new Error(`ํ์ผ์ ๋ถ๋ฌ์ค๋๋ฐ ์คํจํ์ต๋๋ค: ${response.statusText}`);
}
// 3. ์๋ต ๋ณธ๋ฌธ์ ํ
์คํธ ํ์์ผ๋ก ์ฝ๊ธฐ (๋น๋๊ธฐ ๋๊ธฐ)
const shaderCode = await response.text();
console.log("์
ฐ์ด๋ ๋ก๋ ์๋ฃ!");
return shaderCode;
} catch (error) {
// ๋คํธ์ํฌ ์ค๋ฅ๋ ํ์ผ ๋ถ์ฌ ์ ์๋ฌ ์ฒ๋ฆฌ
console.error("์
ฐ์ด๋ ๋ก๋ฉ ์๋ฌ:", error);
return null;
}
}
// ์คํ ์์
async function initWebGL() {
console.log("์ด๊ธฐํ ์์...");
// ๋น๋๊ธฐ ํจ์ ํธ์ถ ๋ฐ ๊ฒฐ๊ณผ ๋๊ธฐ
const vertexShaderSource = await loadShaderSource('./shaders/vertex.glsl');
const fragmentShaderSource = await loadShaderSource('./shaders/fragment.glsl');
if (vertexShaderSource && fragmentShaderSource) {
// ์
ฐ์ด๋ ์ปดํ์ผ ๋ฐ WebGL ํ๋ก๊ทธ๋จ ์์ฑ ๋จ๊ณ๋ก ์ง์
console.log("์
ฐ์ด๋ ์์ค ์ค๋น ์๋ฃ. ์ปดํ์ผ์ ์์ํฉ๋๋ค.");
} else {
console.error("์
ฐ์ด๋ ์์ค๊ฐ ์์ด ํ๋ก๊ทธ๋จ์ ์คํํ ์ ์์ต๋๋ค.");
}
}
initWebGL();