Começando com Three.js, imersão com 3D no navegador
Tags: threejs, imersive, 3d, webgl
Published: 2024-03-29 19:21:35

Este artigo é a segunda parte do tutorial, recomendo que veja a primeira caso ainda não tenha visto - [Parte 1](https://dev.to/baltz/comecando-com-threejs-renderizando-3d-no-navegador-3d3o)

Abaixo vou deixar um spoiler do que vamos desenvolver agora:

{% codepen https://codepen.io/baltazarparra/pen/eYoGVdW %}

Continuando do estado em que terminamos a primeira parte:

index.html
```html
<!DOCTYPE html>
<html lang="pt-br">
  <head>
    <meta charset="utf-8" />
    <title>Meu primeiro 3D</title>
    <style>
      body {
        margin: 0;
      }
    </style>
  </head>
  <body>
    <canvas id="c"></canvas>
    <script type="module" src="/main.js"></script>
  </body>
</html>
```

```js
import * as THREE from "three";

function main() {
  const canvas = document.querySelector("#c");
  const renderer = new THREE.WebGLRenderer({ antialias: true, canvas });

  const camera = new THREE.PerspectiveCamera(75, 2, 0.1, 5);
  camera.position.z = 2;

  const scene = new THREE.Scene();
  const geometry = new THREE.BoxGeometry(1, 1, 1);
  const material = new THREE.MeshBasicMaterial({ color: 0x44aa88 });
  const cube = new THREE.Mesh(geometry, material);

  scene.add(cube);
  renderer.render(scene, camera);
}

main();
```

Já possuímos um modelo 3D renderizado no navegador. Agora, vamos adicionar uma camada de imersão para aprimorar nossa experiência. Ao final deste artigo, teremos um novo projeto 3D imersivo pronto para ser adicionado aos nossos destaques no GitHub.

Para começar, vamos tornar nosso Canvas responsivo a qualquer tamanho de tela. Isto pode ser feito adicionando o seguinte estilo:

index.html
```css
<style>
      body, html {
        margin: 0;
        height: 100vh;
      }

      #c {
        position: absolute;
        height: 100%;
        width: 100%;
        display: block;
      }
</style>
```

Vamos adicionar a propriedade "alpha" ao nosso Renderer e definir um tamanho ao Canvas usando o método setSize. Além disso, vamos ajustar a perspectiva da nossa câmera:

main.js
```js
  const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true, canvas: canvas });
  renderer.setSize(window.innerWidth, window.innerHeight);

  const camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );
```

Agora que temos um canvas responsivo que renderiza nosso modelo 3D corretamente em qualquer tamanho de tela, podemos começar a adicionar imersão à nossa experiência. Para isso, vamos começar a interagir com os movimentos do mouse:

main.js
```js
  function render() {
    document.addEventListener("mousemove", (event) => {
      let mouseX = event.clientX;
      let mouseY = event.clientY;

      cube.rotation.x = mouseY * 0.008;
      cube.rotation.y = mouseX * 0.0036;
    });

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }
```

Ótimo! Agora temos uma experiência imersiva com um modelo 3D. Conquistamos nossa pequena vitória do dia, e como bônus, vamos um pouco além (mas não fique mal acostumado). Vamos tornar nosso projeto mais atraente e digno de destaque no nosso GitHub, adicionando iluminação e explorando formas e materiais mais complexos.

main.js
```js
import * as THREE from "three";

function main() {
  const canvas = document.querySelector("#c");
  const renderer = new THREE.WebGLRenderer({
    antialias: true,
    canvas,
    alpha: true,
  });
  renderer.setSize(window.innerWidth, window.innerHeight);

  const fov = 75;
  const near = 0.1;
  const far = 1000;
  const camera = new THREE.PerspectiveCamera(
    fov,
    window.innerWidth / window.innerHeight,
    near,
    far
  );

  camera.position.z = 30;

  const scene = new THREE.Scene();
  const geometry = new THREE.TorusKnotGeometry(10, 3, 100, 16);

  const material = new THREE.MeshPhysicalMaterial({
    metalness: 0, // High metalness for ruby-like shine
    roughness: 0, // Low roughness for smooth, glossy surface
    clearcoat: 0,
    clearcoatRoughness: 1,
    transmission: 0,
    color: 0xaa1133,
  });

  const cube = new THREE.Mesh(geometry, material);

  scene.add(cube);

  renderer.render(scene, camera);

  function render() {
    document.addEventListener("mousemove", (event) => {
      let mouseX = event.clientX;
      let mouseY = event.clientY;

      cube.rotation.x = mouseY * 0.008;
      cube.rotation.y = mouseX * 0.0036;
    });

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }
  requestAnimationFrame(render);

  const light = new THREE.SpotLight(0xff22aa, 300, 1000);
  light.position.set(1, 1, 10);
  light.angle = 0.1;
  light.penumbra = 10;
  scene.add(light);
}

main();

```

e vamos aproveitar para atualizar nossa index.html

```html
<!DOCTYPE html>
<html lang="pt-br">
  <head>
    <meta charset="utf-8" />
    <title>Meu primeiro 3D</title>
    <style>
      html,
      body {
        margin: 0;
        height: 100%;
        display: flex;
        justify-content: center;
        align-items: center;
        background-color: #111;
        font-size: 2em;
        font-family: sans-serif;
      }
      #c {
        position: absolute;
        height: 100%;
        width: 100%;
        display: block;
        opacity: 0.6;
      }
    </style>
  </head>
  <body>
    <canvas id="c"></canvas>
    <h1>Meu primeiro 3D</h1>
    <script type="module" src="/main.js"></script>
  </body>
</html>
```

Espero que tenham gostado 🤙