🌐 Introdução ao React Three Fiber
Para criar uma cena 3D interativa, podemos utilizar a biblioteca React Three Fiber, que nos permite combinar a potência da Three.js com a facilidade de uso de React. Nesta seção, vamos explorar como criar uma cena 3D com React Three Fiber, destacando os principais componentes da cena.
Componentes da Cena
A cena é composta por três principais componentes:
- Grade no plano de fundo: uma grade que reage ao movimento do mouse;
- Tubo cilíndrico de imagens: um tubo que roda e se move verticalmente;
- Capacete de vidro: um capacete que gira em sincronia com o tubo;
Efeitos de Hover e Tooltip
Além dos componentes principais, também vamos adicionar efeitos de hover e tooltip para criar uma experiência mais interativa. O hover fará com que o sistema se mova mais lentamente, enquanto o tooltip mostrará informações adicionais sobre o componente ativo.
Configurando o Ambiente
Para começar, precisamos configurar o ambiente de desenvolvimento com React Three Fiber. Isso inclui a instalação das dependências necessárias e a criação de um componente principal para renderizar a cena.
import React from 'react';
import { Canvas } from '@react-three/fiber';
function App() {
return (
<Canvas>
{/* Cena aqui */}
</Canvas>
);
}
export default App;
Agora que temos o ambiente configurado, podemos começar a criar a cena 3D com React Three Fiber.
🔄 Movimento como Sinal Compartilhado
Introdução
Em vez de tratar cada interação separadamente, permitimos que tudo afete o mesmo sistema de movimento. Isso significa que a rolagem move a tubulação verticalmente, a velocidade de rolagem adiciona rotação, a posição do mouse muda a forma da grade e o hover reduz a velocidade do tempo.
Atualização do Sinal de Movimento
Os valores importantes vivem dentro de useRef:
const tubeScrollTarget = useRef(0);
const tubeSpinVelocity = useRef(0);
const tubeAngle = useRef(0);
const rotationSpeedScaleTargetRef = useRef(1);
Dentro de useFrame, atualizamos tudo a cada frame:
useFrame((_state, dt) => {
scrollCurrent.current +=
(scrollTargetRef.current - scrollCurrent.current) * 0.12;
spinVelocityRef.current *= Math.pow(0.92, dt * 60);
rotationSpeedScale.current +=
(rotationSpeedScaleTargetRef.current - rotationSpeedScale.current) *
rotationSpeedScaleLerpRef.current;
const scaledDt = dt * rotationSpeedScale.current;
angle.current +=
(baseSpeedRef.current + spinVelocityRef.current) * scaledDt;
tubeAngleRef.current = angle.current;
});
Não usamos o estado de React aqui. Nada re-rendere a cada frame. Tudo fica dentro do loop de animação.
📈 Deformação de Geometria no Vertex Shader
Medição da Distância dos Vértices em Relação à Borda e ao Centro da Grade
varying vec2 vUv;
uniform float uEdgeWidth;
uniform float uEdgeAmp;
uniform float uCenterRadius;
uniform float uCenterAmp;
uniform vec2 uCenter;
void main() {
vUv = uv;
vec3 p = position;
float dEdge = min(
min(vUv.x, 1.0 - vUv.x),
min(vUv.y, 1.0 - vUv.y)
);
float edgeMask = 1.0 - smoothstep(0.0, uEdgeWidth, dEdge);
float dCenter = distance(vUv, uCenter);
float centerMask = 1.0 - smoothstep(0.0, uCenterRadius, dCenter);
float zOffset = edgeMask * uEdgeAmp
+ centerMask * uCenterAmp;
p.z += zOffset;
gl_Position = projectionMatrix * modelViewMatrix * vec4(p, 1.0);
}
Deformação Suave dos Vértices
A deformação é alcançada mediante a medição da distância dos vértices em relação à borda e ao centro da grade. A função `smoothstep` é usada para criar um efeito de transição suave entre os vértices. O parâmetro `uEdgeWidth` controla a largura da borda, enquanto `uCenterRadius` controla o raio do centro. O valor de `zOffset` é calculado como a soma da deformação da borda e do centro, e é adicionado ao vértice para criar o efeito de deformação.
🖌️ Desenhando a Grade no Fragment Shader
Animando a Grade ao Longo do Tempo
A grade é desenhada matematicamente no fragment shader, e a animação da grade ao longo do tempo é feita com a seguinte linha de código:
vec2 uv = (vUv + vec2(uTime * uScrollSpeed, 0.0)) * uGridScale;
Essa linha de código adiciona um componente de tempo à posição da grade, criando um efeito de movimento ao longo do tempo.
Definindo uma Função para Desenhar Linhas
A função para desenhar linhas é definida como:
float gridLine(float coord, float width) {
float fw = fwidth(coord);
float p = abs(fract(coord - 0.5) - 0.5);
return 1.0 - smoothstep(width * fw, (width + 1.0) * fw, p);
}
Essa função utiliza a função `fract` para repetir o padrão de linha infinitamente e a função `smoothstep` para criar um efeito de transição suave entre as linhas.
Criando um Padrão de Grade Infinito e Anti-aliasado
O padrão de grade é criado utilizando a função `gridLine` e a seguinte linha de código:
float gx = gridLine(uv.x, uLineWidth);
float gy = gridLine(uv.y, uLineWidth);
float g = max(gx, gy);
Essa linha de código cria um padrão de grade infinito e anti-aliasado, utilizando a função `gridLine` para desenhar as linhas e a função `max` para determinar a cor da grade.
Utilizando Técnicas de Anti-aliasamento
A técnica de anti-aliasamento é utilizada com a função `fwidth` para criar um efeito de transição suave entre as linhas:
float fw = fwidth(coord);
Essa função cria um efeito de anti-aliasamento, reduzindo a aparência de linhas retas e criando um efeito de transição suave entre as linhas.
🔄 Looping Vertical Sem Interrupções
Reposicionamento do Tubo
Para criar um efeito de looping vertical sem interrupções, precisamos repositionar o tubo quando necessário. Isso é feito ajustando a posição atual e o valor alvo do tubo para evitar saltos visíveis.
if (scrollCurrent.current > loopHeight / 2) {
scrollCurrent.current -= loopHeight;
scrollTargetRef.current -= loopHeight;
}
Posicionamento das Imagens
Cada imagem é posicionada em torno de um círculo usando as seguintes equações:
const theta = ((col + rowOffset) / cols) * Math.PI * 2;
const x = Math.cos(theta) * radius;
const z = Math.sin(theta) * radius;
const ry = -(theta + Math.PI / 2);
Essas equações calculam a posição da imagem em relação ao centro do círculo, garantindo que cada imagem esteja posicionada de forma a criar um efeito de looping vertical sem interrupções.
Fonte de Referência: tympanus.net.
Curadoria e Adaptação: Redação Yassutaro Developers.