Menu fechado

Crie uma Experiência de 3D Hipnótica com React Three Fiber

React Three Fiber

🌐 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.



Redação YTI&W-News

Redação Developers | Yassutaro TI & Web

Notícias do universo do Desenvolvimento Web, dicas e tutoriais para Webmasters.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Publicado em:Desenvolvimento Web
Fale Conosco
×

Inscreva-se em nossa Newsletter!


Receba nossos lançamentos e artigos em primera mão!