프레넬 림 라이트

Fresnel rim light

표면을 정면으로 볼 때는 흐리고 비스듬히(가장자리)로 볼 때는 밝게 빛나 보이게 만드는 셰이더 효과.

다른 이름: Fresnel effectRim lightingEdge glow
···
js
import * as THREE from 'three';
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x030308);
const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100);
camera.position.set(0, 0, 4.4);

const vertexShader = [
  'varying vec3 vNormal;',
  'varying vec3 vViewDir;',
  'void main() {',
  '  vNormal = normalize(normalMatrix * normal);',
  '  vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);',
  '  vViewDir = normalize(-mvPosition.xyz);',
  '  gl_Position = projectionMatrix * mvPosition;',
  '}',
].join('\n');

const fragmentShader = [
  'varying vec3 vNormal;',
  'varying vec3 vViewDir;',
  'uniform vec3 uCore;',
  'uniform vec3 uRim;',
  'uniform float uPower;',
  'void main() {',
  '  float fresnel = pow(1.0 - clamp(dot(normalize(vNormal), normalize(vViewDir)), 0.0, 1.0), uPower);',
  '  vec3 color = mix(uCore, uRim, fresnel);',
  '  gl_FragColor = vec4(color, fresnel * 0.5 + 0.5);',
  '}',
].join('\n');

const mat = new THREE.ShaderMaterial({
  uniforms: {
    uCore: { value: new THREE.Color(0x0c1a3a) },
    uRim: { value: new THREE.Color(0x5fd0ff) },
    uPower: { value: 2.2 },
  },
  vertexShader,
  fragmentShader,
  transparent: true,
});
const mesh = new THREE.Mesh(new THREE.IcosahedronGeometry(1.4, 5), mat);
scene.add(mesh);

function resize() { renderer.setSize(innerWidth, innerHeight); camera.aspect = innerWidth / innerHeight; camera.updateProjectionMatrix(); }
addEventListener('resize', resize); resize();
renderer.setAnimationLoop((t) => {
  mesh.rotation.y = t * 0.0003;
  mesh.rotation.x = Math.sin(t * 0.0002) * 0.4;
  renderer.render(scene, camera);
});

프레넬 효과는 원래 유리·물 같은 표면에서 보는 각도에 따라 반사율이 달라지는 실제 광학 현상입니다. 셰이더에서는 표면 법선(normal)과 시선 방향(view direction)의 내적을 이용해 흉내 냅니다: fresnel = pow(1.0 - dot(normal, viewDir), power). 시선과 법선이 거의 수직(가장자리)이면 dot 값이 0에 가까워져 fresnel이 1에 가까워지고, 정면으로 보면 dot이 1에 가까워 fresnel이 0에 가깝습니다.

pow()의 지수(power)로 이 전환이 얼마나 좁고 날카로운 테두리로 보일지 조절합니다. 데모는 이 fresnel 값으로 core 색(짙은 남색)과 rim 색(밝은 시안)을 mix()하고, 알파값도 fresnel에 연동해 가장자리만 불투명하게 만들어 홀로그램 같은 룩을 냅니다.

물리적으로 정확한 프레넬 방정식(Schlick 근사 등)도 있지만, UI·이펙트 목적이라면 이 단순화한 pow() 버전으로 충분히 그럴듯합니다.

언제 쓰나

홀로그램·에너지 실드 같은 SF 이펙트, 3D 오브젝트의 실루엣을 강조하고 싶을 때.