Implementing a Foil Sticker Effect
Эффект фольги в Three.js
Создаём шейдер, имитирующий голографическую наклейку: угловая иризация + блёстки.
Иризация
Цвет меняется с углом обзора: отражённый вектор → HSL-оттенок, имитируем тонкоплёночную интерференцию.
Блёстки
Процедурный шум (2D-случайные точки) даёт блестящие частицы, которые мигают при движении камеры.
Реализация
PBR-параметры используются как художественный приём, а не физика.
Вершинный шейдер
uniform float uPeelAmount, uPeelAngle;
varying vec2 vUv; varying vec3 vWorldPos, vNormal; varying float vAOIntensity;
void main() {
vUv = vec2(uv.x, 1.0 - uv.y);
vec3 pos = position, hinge = vec3(0);
vec3 toVertex = pos - hinge;
float peelFactor = (uv.x + uv.y) * 0.5;
float angle = radians(uPeelAngle) * uPeelAmount * peelFactor;
vec3 axis = normalize(vec3(cos(radians(uPeelAngle + 90.)), sin(radians(uPeelAngle + 90.)), 0));
float c = cos(angle), s = sin(angle);
pos = pos * c + cross(axis, pos) * s + axis * dot(axis, pos) * (1.0 - c);
vNormal = normalize(normalMatrix * (normal * c + cross(axis, normal) * s + axis * dot(axis, normal) * (1.0 - c)));
vAOIntensity = peelFactor * uPeelAmount;
vWorldPos = (modelMatrix * vec4(pos, 1.0)).xyz;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
Фрагментный шейдер
uniform vec3 uBaseColor, uLightDir;
uniform float uMetalness, uRoughness, uFoilScale, uFlakeDensity, uFlakeSize;
varying vec2 vUv; varying vec3 vWorldPos, vNormal; varying float vAOIntensity;
float hash(vec2 p) { return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453); }
vec3 hueShift(vec3 c, float h) { return c * cos(h) + vec3(-.14861, 1.78277, -.29227) * sin(h); }
void main() {
vec3 N = normalize(vNormal), V = normalize(cameraPosition - vWorldPos);
float NdotV = max(dot(N, V), 0.0);
float fresnel = pow(1.0 - NdotV, 4.0);
vec2 uv = vUv * uFoilScale;
float flake = smoothstep(1.0 - uFlakeSize, 1.0, hash(floor(uv * uFlakeDensity)) * hash(floor(uv * uFlakeDensity * 10.0)));
vec3 iridescence = hueShift(uBaseColor, NdotV * 6.28318);
vec3 color = mix(uBaseColor, iridescence, fresnel) + vec3(flake) * uMetalness;
color *= 1.0 - vAOIntensity * 0.5;
gl_FragColor = vec4(color, 1.0);
}
Лицензия
MIT.