
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 );
});