Conteúdo deste artigo
- Master GSAP Web Animation
- Conceito: Conforto que não existe
- Projetando recursos visuais semelhantes a pinturas
- Tech Stack
- Kuwahara Shader: Definindo a identidade do projeto
- The Reflective Water
- Gerando pão no clique
- Revelar efeito para a introdução #
- Efeitos sonoros e interação
- Design responsivo
- Considerações finais
- Créditos
Como seria se uma experiência web 3D Three.js/WebGL se comportasse como uma pintura em aquarela – fluida, responsiva e interativa? Em Susurrus , exploro essa ideia usando a renderização não fotorrealista (NPR), abordando a estilização como uma consideração estética e de desempenho. Neste estudo de caso, explicarei como esse projeto foi concebido e construído.
Conceito: Conforto que não existe
Um moinho de vento esquecido flutua na água, renderizado com a delicadeza de uma aquarela, mas totalmente 3D e interativo. Em Susurrus , a cena parece natural e aconchegante à primeira vista, mas sutilmente surreal e absurda após uma inspeção mais detalhada. O design de som suave e uma atmosfera calma criam um espaço meditativo e lo-fi.
Por trás dos visuais aconchegantes, surge uma sutil estranheza: um moinho submerso produzindo pão incessantemente, embora os grãos já devessem ter desaparecido há muito tempo – um símbolo silencioso de conforto inexistente.
Projetando recursos visuais semelhantes a pinturas
Como sempre, raramente uso Figma ou outras ferramentas de design para projetos pessoais. Prefiro uma abordagem de estilo livre, explorando ideias a partir de um conceito breve. O processo de design parece um eco em minha mente: quero ter uma casa flutuando em água refletiva, com o shader Kuwahara aplicado como pós-processamento para criar uma experiência web 3D semelhante a uma pintura.
A UI/UX é intuitiva e clara, com foco em conteúdo 3D. Dois poetas são apresentados, mas a mensagem central é a emoção e a atmosfera – expressas através de imagens e sons. Assim como o nome Susurrus , as palavras são sutis e pouco claras, mais para transmitir uma vibração do que um significado literal.
Tech Stack
- React
- React Three Fiber
- Drei
- Reagir Três Rapier
- Howler.js
- TypeScript
- WebGL
- HTML / SCSS
Kuwahara Shader: Definindo a identidade do projeto
Todo o estilo visual do Susurrus é baseado no shader Kuwahara. Embora possa parecer muito processado, o shader Kuwahara é na verdade a única passagem de pós-processamento no projeto, e tudo é construído em torno dele. Algumas configurações e shaders personalizados são usados para “enganar” sutilmente os olhos e obter o efeito final.
Neste projeto comecei com ele como primeiro passo – antes mesmo de terminar os modelos 3D no Blender. Essa abordagem me permitiu ajustar os efeitos visuais antecipadamente e evitar resultados inesperados de sombreamento posteriormente.
Pesquisei diferentes abordagens para implementar o shader Kuwahara e encontrei vários recursos úteis online. A referência que mais me inspirou foi o blog de Maxime Heckel , onde ele explica claramente o filtro Kuwahara e explora técnicas de sombreamento pictórico.
Com base nessas referências, desenvolvi minha própria implementação simplificada durante o projeto, focando em uma abordagem mais leve e limitada:
- Eu não usei
TensorPasspara manter a passagem simples, mesmo que possa aprimorar os detalhes. - Eu uso uma abordagem de estágio de vértice diferente em comparação com implementações de shader Kuwahara padrão.
varying vec2 vUv; void main() { vUv = uv; vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0); // Set the final position of the vertex gl_Position = projectionMatrix * modelViewPosition; }
E o código de vértice do meu shader Kuwahara é:
varying vec2 vUv; void main() { vUv = uv; gl_Position = vec4(position, 1.0);
Não usei as matrizes modelViewProjection (MVP) completas para manter os cálculos um pouco mais rápidos, com a desvantagem de que o efeito é mais fraco quando a câmera se aproxima muito – mas como a câmera não é animada para se aproximar dos modelos, isso funciona bem.
Aqui está minha versão do Kawahara Pass que usei em Susurrus:
The Reflective Water
A água reflexiva é realmente feita de forma suja, são apenas três etapas:
- 1. Usado
varying vec2 vUv; void main() { vUv = uv; vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0); // Set the final position of the vertex gl_Position = projectionMatrix * modelViewPosition; }, com o estilo aquarela, a resolução pode ser muito baixo, mantendo o desempenho estável tanto em dispositivos móveis quanto em computadores. - 2. Criei um shader personalizado e apliquei-o a um plano acima do plano
varying vec2 vUv; void main() { vUv = uv; vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0); // Set the final position of the vertex gl_Position = projectionMatrix * modelViewPosition; }, adicionando mais detalhes e animação à água. - 3. Relâmpago ajustado para que a água pareça mais viva, não muito plana ou chata.
Gerando pão no clique
O conceito é sobre construir uma pintura dinâmica, então pensei que seria seria interessante implementar a física neste projeto. O Pão Gerador é apresentado como o principal elemento interativo do Susurrus.
Revelar efeito para a introdução #
Em relação ao desempenho, usei MeshReflectorMaterial para controlar o shader de revelação uProgress e apliquei o shader a um MeshReflectorMaterial, que é uma maneira muito útil de implementar o efeito de revelação da introdução.
const RevealOverlay = ({ visible = true }: { visible?: boolean }) => { const materialRef = useRef<THREE.ShaderMaterial>(null!); const meshRef = useRef<THREE.Mesh>(null!); const scroll = useScroll(); const uniforms = useMemo( () => ({ uProgress: { value: 0 }, }), [], ); useEffect(() => { if (meshRef.current) { meshRef.current.raycast = () => null; } }, []); useFrame(() => { if (!materialRef.current) return; let offset = scroll.offset; if (offset < 0.001) offset = 0; materialRef.current.uniforms.uProgress.value = offset * 0.9; }); if (!visible) return null; return ( <ScreenQuad ref={meshRef} renderOrder={-1}> <shaderMaterial ref={materialRef} transparent depthWrite={false} uniforms={uniforms} vertexShader={revealVertexShader} fragmentShader={revealFragmentShader} side={THREE.FrontSide} depthTest={false} /> </ScreenQuad> ); }; export default RevealOverlay;
Efeitos sonoros e interação
Eu usei ScrollControls para implementar efeitos sonoros. Diferentes interações de áudio podem ser acionadas ao passar o mouse ou clicar. Os efeitos sonoros são integrados à música de fundo para obter um estilo lo-fi, o que faz com que Susurrus pareça uma pintura que pode cantar.
Design responsivo
Como sempre, meu objetivo é a compatibilidade móvel e o bom desempenho em dispositivos móveis e também em dispositivos mais antigos.
Considerações finais
Antes da IA se tornar tão poderosa, às vezes eu me preocupava que meu trabalho fosse muito estranho. Mas à medida que a IA se tornou mais capaz, a minha mentalidade mudou. Nesta era da IA, a exclusividade parece mais importante hoje em dia. Se meus projetos pessoais são distintos o suficiente para deixar uma leve impressão, ou fazer alguém parar por um milésimo de segundo e pensar: “o que é isso?” – isso é suficiente para me orgulhar. Também me leva a experimentar mais em meu trabalho pessoal.
Créditos
Ativos 3D:
(fornecido e modificado para este projeto)
- Bram Verheyen – Aldeias DAE | Padaria Grega Antiga (Sketchfab)
- Rocco Giandomenico – Piso de madeira estilizado de baixo poliéster (Sketchfab)
- Alienn27 – Low Poly Boat (Sketchfab)
Música e efeitos sonoros:
