레슨 4 / 8·20분
텍스처와 샘플링
텍스처 매핑과 UV 좌표
텍스처는 셰이더에서 이미지 데이터를 읽어 픽셀 색상에 반영하는 핵심 기법입니다. sampler2D 타입으로 텍스처를 선언하고, texture2D() 함수로 특정 UV 좌표의 색상을 샘플링합니다. UV 좌표는 (0,0)이 왼쪽 아래, (1,1)이 오른쪽 위이며, 이 좌표를 조작하면 텍스처를 이동, 회전, 반복, 왜곡할 수 있습니다.
glsl
precision mediump float;
uniform sampler2D u_texture; // 텍스처 (JS에서 바인딩)
uniform vec2 u_resolution;
uniform float u_time;
void main() {
// UV 좌표 계산 (0~1 정규화)
vec2 uv = gl_FragCoord.xy / u_resolution;
// ── 기본 텍스처 샘플링 ──
vec4 texColor = texture2D(u_texture, uv);
gl_FragColor = texColor;
}glsl
precision mediump float;
uniform sampler2D u_texture;
uniform vec2 u_resolution;
uniform float u_time;
void main() {
vec2 uv = gl_FragCoord.xy / u_resolution;
// ── UV 좌표 변환 ──
// 1. 텍스처 반복 (타일링)
vec2 tiledUV = fract(uv * 3.0); // 3x3 반복
// 2. 텍스처 스크롤 (이동)
vec2 scrollUV = uv + vec2(u_time * 0.1, 0.0);
scrollUV = fract(scrollUV); // 반복되도록 감싸기
// 3. 텍스처 회전
float angle = u_time * 0.5;
vec2 center = vec2(0.5);
vec2 rotatedUV = uv - center;
rotatedUV = vec2(
rotatedUV.x * cos(angle) - rotatedUV.y * sin(angle),
rotatedUV.x * sin(angle) + rotatedUV.y * cos(angle)
);
rotatedUV += center;
// 4. 텍스처 줌
vec2 zoomUV = (uv - 0.5) * 0.5 + 0.5; // 2배 확대 (중앙 기준)
// 5. 물결 왜곡
vec2 waveUV = uv;
waveUV.x += sin(uv.y * 10.0 + u_time) * 0.03;
waveUV.y += cos(uv.x * 10.0 + u_time) * 0.03;
vec4 color = texture2D(u_texture, waveUV);
gl_FragColor = color;
}javascript
// JavaScript에서 텍스처 로딩 및 바인딩
const gl = canvas.getContext('webgl');
function loadTexture(url) {
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
// 로딩 중 임시 픽셀 설정
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0,
gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 255, 255]));
const image = new Image();
image.crossOrigin = 'anonymous';
image.onload = function () {
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,
gl.RGBA, gl.UNSIGNED_BYTE, image);
// 텍스처 래핑 모드
gl.texParameteri(gl.TEXTURE_2D,
gl.TEXTURE_WRAP_S, gl.REPEAT); // 수평 반복
gl.texParameteri(gl.TEXTURE_2D,
gl.TEXTURE_WRAP_T, gl.REPEAT); // 수직 반복
// 필터링 모드
gl.texParameteri(gl.TEXTURE_2D,
gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D,
gl.TEXTURE_MAG_FILTER, gl.LINEAR);
};
image.src = url;
return texture;
}
// 텍스처를 셰이더에 전달
const tex = loadTexture('image.jpg');
const uTexture = gl.getUniformLocation(program, 'u_texture');
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.uniform1i(uTexture, 0); // TEXTURE0 유닛 번호- •sampler2D — 텍스처를 참조하는 데이터 타입
- •texture2D(sampler, uv) — UV 좌표에서 텍셀(픽셀) 색상 읽기
- •fract(uv * n) — UV 좌표를 n번 반복(타일링)
- •TEXTURE_WRAP_S/T — REPEAT(반복), CLAMP_TO_EDGE(고정) 등
- •TEXTURE_MIN/MAG_FILTER — LINEAR(부드러움), NEAREST(픽셀화)
- •gl.activeTexture(gl.TEXTUREn) — 텍스처 유닛 활성화
💡
텍스처 크기가 2의 거듭제곱(256, 512, 1024)이 아니면 WebGL 1에서 REPEAT 래핑과 밉맵을 사용할 수 없습니다. NPOT(Non-Power-Of-Two) 텍스처는 CLAMP_TO_EDGE와 LINEAR 필터링만 지원됩니다. WebGL 2에서는 이 제한이 없습니다.