Quello che non ti dicono di Three.js – Parte 2

Come nella Parte 1, ci occuperemo di indicare in questo post tutti quegli spunti e riflessioni su Three.js che da uno studio superficiale della libreria potrebbero sfuggire. Sono argomenti tecnici particolari e profondi che però cercano di mettere in guardia lo sviluppatore da potenziali problemi ed errori.

La funzione repeat delle textures di un materiale è condivisa

Da come è strutturata la gestione delle singole textures può sembrare che applicando il .repeat.set questo possa essere fatto indipendentemente su qualsiasi mappa del materiale, ad esempio map(1,1) e emissiveMap(3,3). In realtà non è così in quanto il repeat è condiviso su tutte le mappe del materiale, con questa priorità:

  • color map
  • specular map
  • displacement map
  • normal map
  • bump map
  • roughness map
  • metalness map
  • alpha map
  • emissive map

Questo NON si applica alla “light map”, alla “ao map” e alla “env map” che invece sono riferite ad un uv set differente.

In sostanza Three.js considera che tutto quello che riguarda la definizione del materiale in sé abbia lo stesso repeat, mentre ciò che riguarda la definizione di attività esterne al materiale (appunto luci o ambiente) abbia un repeat differente. E’ quindi inutile impostare tutti i repeat se si hanno mappe diverse ma unicamente quello della color map (se ovviamente si ha la color).

Il calcolo delle dimensioni del BoundingBox di una TextGeometry è sbagliato

Purtroppo il primo approccio che si pensa al calcolo delle dimensioni di un elemento TextGeometry è quello di utilizzare la funzione getSize della geometria, come segue:

let textMeshMeasures = new THREE.Vector3();
textMesh.geometry.boundingBox.getSize(textMeshMeasures);

Purtroppo tale calcolo risulta essere errato in quanto non tiene in considerazioni eventuali scalature, padding etc.

Per eseguire correttamente il calcolo delle dimensioni (width, height, depth) è necessario usare questo approccio (il quale è utilizzato anche nel file BoxHelper di Threejs stesso):

let box = new THREE.Box3();
box = box.setFromObject(textMesh);
let textMeshMeasures = new THREE.Vector3();
box.getSize(textMeshMeasures);

Il raycast può dare problemi con elementi di tipo Line

Ad esempio quando si esegue il raycast per individuare gli oggetti cliccati in scena, l’oggetto Raycaster ritorna un array di intersezioni con tutti gli oggetti coinvolti. Se in scena sono presenti delle mesh creare con THREE.Line può includere intersezioni non veritiere (dopotutto a chi può servire fare un raycast su delle linee). Il consiglio è quindi, prima di interrogare l’array, di eseguire una funzione .filter sull’array.

Per disegnare il raggio è possibile usare questa funzione:

let arrow = new THREE.ArrowHelper(raycaster.ray.direction, raycaster.ray.origin, 100, Math.random() * 0xff0000);

Gestione dello z-fighting

Può capire di dover gestire lo z-fighting per poligoni con la stessa coordinata (ad esempio con z = 0). Lo z-fighting è quell’artefatto grafico dove la pipeline di rendering non capisce quale poligono disegnare prima di un altro e dunque può generare problemi di visualizzazione. Una delle soluzioni è spostare di poco la coordinate per gli elementi che si vogliono renderizzare prima/dopo. In ThreeJS esiste però un altro metodo da applicare al materiale del poligono stesso, da usare nel modo seguente:

material.depthTest: true,
material.depthWrite: false,
material.polygonOffset: true,
material.polygonOffsetFactor: -4

più il valore di Factor è inferiore (anche negativo) e più il poligono viene renderizzato per primo.
E’ da indicare che questo metodo non funziona con poligoni associati a LineBasicMaterial.

Gestione dell’ordine delle trasparenze

Sfortunatamente, l’alpha blending (material.transparent = true) introduce molta complessità nel processo di rendering e rende i risultati molto sensibili all’ordine di rendering. Anche quando si imposta material.opacity=1, si possono comunque ottenere risultati significativamente diversi rispetto a un oggetto opaco con material.transparent = false. Non esistono soluzioni “perfette” che funzionino in tutti i casi, ma ci sono alcune soluzioni alternative che si possono provare:

  • Utilizzare material.DepthWrite = true sui materiali trasparenti
  • Impostare material.transparent=false una volta che l’opacità dell’oggetto è a 1
  • Impostare renderer.sortObjects: true
https://www.desdinova.it
Aiuto aziende e professionisti che hanno bisogno di sviluppare in modo creativo, alternativo ed efficace la loro identità digitale e che desiderano ottenere visibilità e risultati concreti attraverso lo sviluppo di strumenti online dall'elevata innovazione e personalizzazione (3D, Realtà Virtuale, Realtà Aumentata, Advergame, etc)
Daniele Ferla
Aiuto aziende e professionisti che hanno bisogno di sviluppare in modo creativo, alternativo ed efficace la loro identità digitale e che desiderano ottenere visibilità e risultati concreti attraverso lo sviluppo di strumenti online dall'elevata innovazione e personalizzazione (3D, Realtà Virtuale, Realtà Aumentata, Advergame, etc)

Must Read