Aguarde...

9 de agosto de 2022

10 Dicas do Three.JS

10 Dicas do Three.JS

Não 1. Usando scene.overrideMaterial

Você sabia que a classe Scene possui uma propriedade overrideMaterial? Se estiver definido, todas as malhas serão renderizadas usando este material. Você pode fazer um fork para brincar com ele ou exportá-lo como um arquivo zip. Vamos dar uma olhada no código JS.

import * as THREE from 'three';
import GUI from 'https://unpkg.com/three@0.142.0/examples/jsm/libs/lil-gui.module.min.js';

Observe que estou usando módulos carregados de unpkg.com . Os exemplos mais recentes do Three.JS usam mapas de importação , permitindo que o desenvolvedor mapeie uma string para um URL. Minhas dicas usam o mesmo método.

<script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/three@0.142.0/build/three.module.js"
    }
  }
</script>

O código relevante para esta dica começa na linha 51.

const mat = new THREE.MeshBasicMaterial( { color: 0xFFFFFF, wireframe: true });
  const gui = new GUI();
  const options = { 
    overrideMaterial: false, 
    background: 0x000000,
    lights: true
  }
  gui.add(options, 'overrideMaterial').onChange( value => {
    if (value){
      scene.overrideMaterial = mat;
    }else{
      scene.overrideMaterial = null;
    }
  });

Eu crio um MeshBasicMaterial , que não usa iluminação. A cor é definida como branca e o wireframe é verdadeiro. Eu adiciono uma GUI usando a biblioteca lil-gui um substituto direto para dat.gui . Eu adiciono um controle de gui para overrideMaterial com um evento de alteração. Eu uso isso para alternar entre atribuir o MeshBasicMaterial ou null a scene.overrideMaterial . Isso pode ser útil ao depurar suas cenas.

Não 2. Defina uma cena.cor de fundo

Por padrão, a cor de fundo da cena é preta. Se você usar materiais que dependem de luzes, mas esquecer de adicionar uma luz, você se deparará com o preto. Ao definir uma cor de fundo, você verá uma silhueta de suas malhas. No exemplo, mesmo link CodePen da dica 1. Eu uso o método addColor da classe GUI para adicionar um controle que nos permite atualizar a cor scene.background .

gui.addColor(options, 'background').onChange( col => {
  scene.background = new THREE.Color(col);
});

Não 3. Defina a cena.ambiente

Se estiver usando um MeshStandardMaterial com rugosidade diferente de 1, você precisará definir um ambiente de cena para refletir. Isso se aplica a qualquer objeto carregado usando a classe GLTFLoader , que usa MeshStandardMaterial . Esta função setEnvironment mostra um método. Link do CodePen .

function setEnvironment(){
  const loader = new RGBELoader();
  const pmremGenerator = new THREE.PMREMGenerator( renderer );
  pmremGenerator.compileEquirectangularShader();
        
  loader.load( 'https://niksgames.com/threejs-games-course/assets/hdr/venice_sunset_1k.hdr', ( texture ) => {
    envmap = pmremGenerator.fromEquirectangular( texture ).texture;
    pmremGenerator.dispose();

    scene.environment = envmap;

  }, undefined, (err)=>{
    console.error( 'An error occurred setting the environment');
    console.error(err);
  } );
}

Eu uso um RGBELoader para um arquivo hdr e um PMREMGenerator . Essa classe gera um PMREM (Mipmapped Radiance Environment Map) pré-filtrado a partir de uma textura de ambiente cubeMap. Isso permite que diferentes níveis de desfoque sejam acessados ​​rapidamente com base na rugosidade do material. O evento loaders onload usa o método fromEquiretangular . O hdr é um mapa de imagem esférico e converte a imagem retangular de volta em uma esfera. Em seguida, arrumamos a memória e configuramos o scene.environment .

Não 4. Renderer.outputEncoding

Se você usar a classe GLTFLoader , certifique-se de definir a propriedade ouputEncoding do renderizador como THREE.sRGBEncoding .

renderer.outputEncoding = THREE.sRGBEncoding;

O padrão é THREE.linearEncoding . A GUI neste exemplo permite que você veja o efeito

Não 5. Renderizador.fisicamenteCorretoLuz

Novamente, se você carregar modelos usando a classe GLTFLoader , defina renderer.physicallyCorrectLights como true. A GUI no exemplo permite que você veja o efeito.

Nº 6 Configurando MatrixAutoUpdate

Se você tiver muitos objetos estáticos em sua cena, obterá um pequeno ganho de desempenho definindo cada propriedade matrixAutoUpdate de malhas como false. Link do CodePen .

function setAutoUpdate(value){
  factory.traverse( child => {
    if (child.isMesh && !child.name.includes('fan')){
      child.matrixAutoUpdate = value;
    }
  })
}

Agora, o método de renderização não precisa calcular a matriz mundial para essas malhas.

No.7 Obtendo os limites de um objeto
A classe Box3 tem um ótimo método para obter os limites alinhados ao eixo de um objeto. Os valores mínimo e máximo dos vértices nos eixos x, yez. A função gui getBounds mostra como. Link do CodePen .

const gui = new GUI();
const options = {
  getBounds: () => {
    const bounds = new THREE.Box3();
    bounds.setFromObject(object);
    alert(`min:${bounds.min.x.toFixed(2)}, ${bounds.min.y.toFixed(2)}, ${bounds.min.z.toFixed(2)} max:${bounds.max.x.toFixed(2)}, ${bounds.max.y.toFixed(2)}, ${bounds.max.z.toFixed(2)}`);
  }
}
gui.add(options, 'getBounds');

Crie um Box3 e use o método setFromObject passando o objeto que você está consultando. O Box3 terá então seu conjunto mínimo e máximo . Nesta função eu os uso para passar uma string para uma caixa de alerta .

Não 8. Camadas

Se você tiver objetos que precisam ser ocultos e mostrados, as camadas são o caminho a seguir. Você precisa habilitar as camadas para a câmera e todas as luzes. Link do CodePen

camera.layers.enable(0);
camera.layers.enable(1);
camera.layers.enable(2);
  	
light.layers.enable( 0 );
light.layers.enable( 1 );
light.layers.enable( 2 );

Então você usa a propriedade layers de um Object3D . Isso tem um método definido quando você escolhe a qual camada esse objeto se aplica.

object.layers.set( layer );//layer is 0, 1 or 2

Tendo feito a configuração, você pode usar a propriedade de camadas da câmera. O método de alternância leva um índice para a camada e ativa e desativa a visibilidade.

const options = {
  'toggle red': ()=>{ camera.layers.toggle(0); },
  'enable all': ()=>{ camera.layers.enableAll(); },
}
gui.add(options, 'toggle red');
gui.add(options, 'enable all');

Three.JS suporta 32 camadas usando os índices inteiros 0-31.

No. 9 SimplifyModifier

Three.JS inclui uma classe SimplifyModifier que reduzirá a contagem de polígonos de uma malha. Infelizmente, atualmente isso não suporta objetos texturizados, os valores uv são perdidos. No exemplo do evento onload eu crio um clone do objeto carregado. O original é armazenado como object.original e o clone como object.simple. Link do CodePen .

loader.load(
  'Nefertiti.glb',
  gltf => {      
    object = { original: gltf.scene.children[0] };
    object.simple = object.original.clone();
    scene.add( object.simple );
  });

Apenas a versão simples é adicionada à cena. O gui tem um controle deslizante para escolher de 0 a 0,9 em passos de 0,1. Um evento change chama a função simplificar .

function simplify(value){
  object.simple.geometry.dispose();
  
  const count = Math.floor(  
    object.original.geometry.attributes.position.count * 
    value ); // number of vertices to remove
  object.simple.geometry = modifier.modify( 
    object.original.geometry, count );
}

Aqui descartamos a geometria simples do objeto. Calcule a contagem de vértices para reduzir. Em seguida, defina a nova geometria usando o método de modificação do SimplifyModifier . Isso leva dois parâmetros a geometria de origem e um valor inteiro do número de vértices para reduzir a contagem de vértices.

No. 10 evento de alteração OrbitControls

Last up é um economizador de bateria em dispositivos móveis. Se sua cena é estática, mas usa OrbitControls , não use um loop de renderização, onde a cena será renderizada até 60 vezes por segundo, o que demanda muito do seu processador desnecessariamente. Em vez disso, adicione um ouvinte de eventos à sua instância OrbitControls , detectando um evento de alteração. Use isso para renderizar sua cena. Link do CodePen .

controls.addEventListener( 'change', () => {
  renderer.render( scene, camera );
});
Postado em Blog
Escreva um comentário