Transições de Shader

Starter pack

Nesta lição, vamos aprender a criar transições usando shaders.

O primeiro efeito que criaremos é um efeito de transição de tela:

Temos controle total sobre o efeito de transição, podemos alterar a duração, a função de easing e o próprio shader.

O segundo efeito que criaremos é um efeito de transição de modelo:

Ao desaparecer, o modelo é dissolvido e as cores são lavadas para branco; o oposto acontece ao aparecer.

Pacote inicial

Aqui estão todos os modelos 3D que usaremos nesta lição, criados por Ergoni e licenciados sob Creative Commons Attribution:

O pacote inicial utiliza os seguintes pacotes:

As duas fontes usadas são Kanit e Rubik Doodle Shadow, ambas do Google Fonts.

Sinta-se livre para ajustar quaisquer componentes conforme suas preferências.

Você pode ajustar as cores brincando com os controles Leva no canto superior direito. Depois de encontrar as cores que você gosta, adicione a prop hidden ao componente Leva em App.jsx:

// ...

function App() {
  // ...
  return (
    <>
      <Leva hidden />
      {/* ... */}
    </>
  );
}

// ...

Transição de tela

Vamos começar criando nosso efeito de transição de tela. Faremos um componente chamado ScreenTransition que lidar com o efeito de transição.

Vamos criar um novo arquivo chamado ScreenTransition.jsx na pasta components:

export const ScreenTransition = ({ transition, color }) => {
  return (
    <mesh>
      <planeGeometry args={[2, 2]} />
      <meshBasicMaterial color={color} />
    </mesh>
  );
};

Neste componente, estamos criando um plano com uma cor que cobrirá a tela inteira. Usaremos este plano para fazer a transição entre telas.

Nosso componente recebe duas props:

  • transition: um booleano para saber se o componente deve exibir o efeito de transição
  • color: a cor principal do efeito de transição

Vamos adicionar o componente ScreenTransition ao App.jsx:

// ...
import { ScreenTransition } from "./components/ScreenTransition";

function App() {
  // ...
  return (
    <>
      {/* ... */}
      <Canvas camera={{ position: [0, 1.8, 5], fov: 42 }}>
        <color attach="background" args={[backgroundColor]} />
        <fog attach="fog" args={[backgroundColor, 5, 12]} />
        <ScreenTransition transition color="#a5b4fc" />
        <Suspense>
          <Experience />
        </Suspense>
      </Canvas>
    </>
  );
}

export default App;

Por enquanto, forçamos o efeito de transição a ser exibido passando true para a prop transition. Adicionaremos a lógica para controlar o efeito de transição mais tarde.

Ajuste a cor ao seu gosto. Se você alterar, certifique-se de atualizar a cor no arquivo index.css para evitar um flash de cor quando o site for carregado:

// ...

html {
  background-color: #a5b4fc;
}

Plane in middle of the scene

O plano está no meio da cena.

Plano em tela cheia

Queremos que nosso plano cubra a tela inteira. Poderíamos usar as dimensões do viewport e fazê-lo ficar de frente para a câmera, mas também queremos que ele esteja sobre tudo.

Para conseguir isso, o Drei fornece um componente chamado Hud que renderizará seus filhos sobre tudo. Podemos adicionar uma câmera fixa ao componente Hud para garantir que esteja perfeitamente alinhada com nosso plano:

import { Hud, OrthographicCamera } from "@react-three/drei";

export const ScreenTransition = ({ transition, color }) => {
  return (
    <Hud>
      <OrthographicCamera
        makeDefault
        top={1}
        right={1}
        bottom={-1}
        left={-1}
        near={0}
        far={1}
      />
      <mesh>
        <planeGeometry args={[2, 2]} />
        <meshBasicMaterial color={color} />
      </mesh>
    </Hud>
  );
};

Usamos uma OrthographicCamera para facilmente cobrir a tela inteira, independentemente da distância entre a câmera e o plano.

Plane covering the entire screen

O plano agora está cobrindo a tela toda.

Lógica de transição

Uma última coisa antes de criar nosso shader personalizado, vamos definir um estado de transição em UI.jsx:

// ...
import { atom } from "jotai";

export const transitionAtom = atom(true);
// ...

Definimos o valor inicial como true para começar com um efeito de fade-out após o carregamento do site.

Usaremos esse estado para controlar o efeito de transição.

Ainda em UI.jsx, vamos definir duas constantes para controlar a duração e o atraso do efeito de transição:

// ...
export const TRANSITION_DELAY = 0.8;
export const TRANSITION_DURATION = 3.2;
// ...

Agora vamos substituir a chamada da função setScreen por uma nova que lidará com o efeito de transição:

// ...
import { useAtom } from "jotai";
import { useRef } from "react";
// ...

export const UI = () => {
  // ...
  const [transition, setTransition] = useAtom(transitionAtom);
  const timeout = useRef();

  // ...
  const transitionToScreen = (newScreen) => {
    setTransition(true);
    clearTimeout(timeout.current);
    timeout.current = setTimeout(() => {
      setScreen(newScreen);
      setTransition(false);
    }, TRANSITION_DURATION * 1000 + TRANSITION_DELAY * 1000);
  };
  // ...
};

Em vez de definir diretamente a nova tela, configuramos o estado de transição para true e usamos um setTimeout para definir a nova tela após o término do efeito de transição (a duração do efeito de transição mais o atraso).

Agora nossa função está pronta, procure por chamadas de setScreen no componente UI e substitua-as por transitionToScreen.

De home para menu:

<motion.button
  onClick={() => transitionToScreen("menu")}
  // ...
>

E de menu para home:

<motion.button
onClick={() => transitionToScreen("home")}
// ...
>

End of lesson preview

To get access to the entire lesson, you need to purchase the course.