| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | 29 |
| 30 |
- #동영상
- #업종별
- #cgimall
- #홈페이지제작
- CGIMALL
- 홈페이지제작
- 사이트제작
- 이미지
- #이미지
- #jQuery
- happycgi
- php
- #해피CGI
- #솔루션
- #image
- javascript
- 해피씨지아이
- 게시판
- #쇼핑몰
- 홈페이지
- 해피CGI
- jquery
- 웹솔루션
- #뉴스
- #홈페이지
- 솔루션
- #happycgi
- #웹솔루션
- CSS
- #CSS
- Today
- Total
웹솔루션개발 25년 노하우! 해피CGI의 모든것
[해피CGI][cgimall] 자바스크립트를 이용한 물방울 효과(VFX) VFX-JS + webfont + dynamic text + raymarching 본문
[해피CGI][cgimall] 자바스크립트를 이용한 물방울 효과(VFX) VFX-JS + webfont + dynamic text + raymarching
해피CGI윤실장 2025. 11. 12. 09:11
자바스크립트로 만든 시각 효과(VFX) 기반의 페이지에서 웹폰트를 사용한 글자를 동적으로 변화시키고,
레이마칭 기술로 화려한 3D 시각 효과를 표현한 디자인입니다.
HTML 구조
<h1 contenteditable>Type<br>here.<br>please.</h1>
CSS 소스
@import url('https://fonts.googleapis.com/css2?family=Cinzel+Decorative:wght@400;700;900&display=swap');
html, body { height: 100%; margin: 0; }
body {
background: black;
background-image: linear-gradient(
340deg,
hsl(220deg 50% 30%) 0%,
hsl(200deg 30% 40%) 20%,
hsl(180deg 20% 50%) 35%,
hsl(220deg 30% 60%) 70%,
hsl(270deg 30% 70%) 90%,
hsl(300deg 30% 70%) 100%
);
display: grid;
place-content: center;
overflow-x: hidden;
}
img {
position: fixed;
width: 100%;
height: 100%;
object-fit: stretch;
}
h1 {
margin: 0;
font-size: 15vh;
line-height: 1.2;
max-width: 100%;
font-family: "Cinzel Decorative";
text-align: center;
color: white;
}
JS 소스
// Using VFX-JS.
import { VFX } from "https://esm.sh/@vfx-js/core@0.6.0";
function lerp(a,b,t) {
return a * (1 - t) + b * t;
}
const shader = `
precision highp float;
uniform vec2 resolution;
uniform vec2 mouse;
uniform vec2 offset;
uniform float time;
uniform sampler2D src;
uniform vec3 mouseDir;
#define PI 3.141593
mat2 rot(float t) {
return mat2(cos(t), -sin(t), sin(t), cos(t));
}
float rand(vec2 p) {
return fract(sin(dot(p, vec2(484., 398.)) * 984.));
}
float sdSphere(vec3 p, float r) {
return length(p) - r;
}
float map(vec3 p) {
// Center sphere
float d = sdSphere(p - mouseDir * 8., 3.);
// Rotate world
p.xz *= rot(sin(time * 0.3) * 0.5);
p.xy *= rot(time * 0.7);
// Place spheres
float l = 4.4;
d = min(d, sdSphere(p + vec3(1, 1, 1) * l, 2.0));
d = min(d, sdSphere(p + vec3(-1, -1, 1) * l * 2., 1.7));
d = min(d, sdSphere(p + vec3(-1, 1, -1) * l, 1.2));
d = min(d, sdSphere(p + vec3(1, -1, -1) * l, 2.9));
return d;
}
vec3 getNormal(vec3 p) {
vec2 d = vec2(1, 0);
return normalize(vec3(
map(p + d.xyy) - map(p - d.xyy),
map(p + d.yxy) - map(p - d.yxy),
map(p + d.yyx) - map(p - d.yyx)
));
}
vec3 spectrum(float x) {
return cos((x - vec3(0, .5, 1)) * vec3(.6, 1., .5) * PI);
}
float surface(vec3 p, vec3 n, vec3 rd, vec3 lig) {
float c = 0.;
// specular
vec3 hal = normalize(lig - rd);
float spe = pow(clamp(dot(hal, n), 0., 1.), 250.);
c += spe * 0.9;
// diffuse
c += clamp(dot(n, lig), 0., 1.) * 0.4;
return c;
}
void main() {
vec2 uv = (gl_FragCoord.xy - offset) / resolution;
vec2 p = uv * 2. - 1.;
p.x *= resolution.x / resolution.y;
p *= resolution.y / 1000.;
vec3 ro = vec3(0, 0, 30);
vec3 rd = normalize(vec3(p, -7));
vec3 rp;
float t = 0.;
float d;
vec4 c = vec4(0);
vec4 light = vec4(0);
vec3 n = vec3(-1);
for (int i = 0; i < 50; i++) {
rp = ro + rd * t;
d = map(rp);
if (d < 0.01) {
n = getNormal(rp);
break;
}
if (t > 50.) {
break;
}
t += d;
}
if (n.z > 0.) {
float glaze = clamp(1. + dot(rd, n), 0., 1.);
// Cheap dispersion
float z = rp.z + 5.; // wall at z = -5.
for (float x = 0.; x <= 1.; x += 0.1) {
float xx = x * 2. - 1.; // remap to [-1, 1]
float ior = 1.5 + x * 2.;
vec3 rd2 = rp + refract(rd, n, 1. / ior);
vec2 uv2 = uv + rd2.xy * z * 0.003 * xx * glaze;
uv2 += rand(rp.xy) * 0.1 * pow(glaze, 3.);
vec4 tc = texture2D(src, uv2);
c += vec4(spectrum(x * 0.7) * 2., 1) * tc.a;
}
c /= 11.;
// fresnel
c += pow(glaze, 3.) * 0.8 * vec4(.6, .9, 1, 1);
// lighting
c += surface(rp, n, rd, normalize(vec3(-.8, 1., .2))) * vec4(.8, .9, 1, 1);
c += surface(rp, n, rd, normalize(vec3(1., -0.7, .1)));
c = clamp(c, 0., 1.);
c += vec4(0.0, 0.02, 0.03, 0.1);
}
// Vignette
c += vec4(0, 0, 0, pow(length(p), 2.) * 0.04);
c += rand(uv * 2.) * 0.1;
c.rgb /= c.a;
gl_FragColor = c;
}
`;
// Constants
const padding = 30;
const lineHeight = 1.2;
const leading = 0.17;
const ratio = window.devicePixelRatio || 1;
// Source element
const e = document.querySelector('h1');
// Canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
const vfx = new VFX();
// Sync text to canvas
function sync() {
// Dimensions
const rect = e.getBoundingClientRect();
canvas.style.position = "fixed";
canvas.style.left = `${rect.left - padding}px`;
canvas.style.top = `${rect.top - padding}px`;
canvas.style.width = `${rect.width + padding * 2}px`;
canvas.style.height = `${rect.height + padding * 2}px`;
canvas.width = (rect.width + padding * 2) * ratio;
canvas.height = (rect.height + padding * 2) * ratio;
canvas.style.pointerEvents = "none";
.
.
.
해당 사이트로 이동하여 전체 소스를 확인하실 수 있습니다.
'웹프로그램밍 자료실 > JAVA 자료' 카테고리의 다른 글
| [해피CGI][cgimall] 긴 글을 더보기 링크로 줄여주는 js - Readmore.js (0) | 2025.11.06 |
|---|---|
| [해피CGI][cgimall] 심플한 노티 js Oh Snap! (0) | 2025.11.05 |
| [해피CGI][cgimall] WebGL Video 전환 Curtains.js (0) | 2025.11.04 |
| [해피CGI][cgimall] 날짜, 시간 계산을 위한 Spacetime (0) | 2025.11.03 |
| [해피CGI][cgimall] TailwindCSS로 스타일링된 최신 jQuery 태그 입력 시스템 (0) | 2025.10.28 |

