Recursos 3JS (aka three.js)

Referências

Modelos

Os modelos abaixo funcionam assumindo que:

  1. Fez o download recomendado;
  2. O arquivo zip foi descompactado para a pasta lib/ da sua diretoria de trabalho;

Isto é, deve obter a seguinte àrvore:

(directoria de trabalho)/
    lib/
        threejs/
            build/
                (vários ficheiros)
            addons/
                jsm/
                    (vários ficheiros)
    (os seus ficheiros de trabalho)

Um documento «standalone>

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>3JS Embebido</title>
		<meta charset="utf-8">
		<script type="importmap">
			{
				"imports": {
					"three": "./lib/threejs/build/three.module.js",
					"three/addons/": "./lib/threejs/addons/jsm/"
				}
			}
		</script>
	</head>

	<body>
		<div id="3js:container">
		</div>

		<script type="module">
// Bibliotecas			
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

// Elemento HTML com o modelo gráfico
const container = document.getElementById("3js:container");
container.width = 512;
container.height = 512;

// Construtor (Renderer) do modelo gráfico
const renderer = new THREE.WebGLRenderer( {alpha: true} );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize(
	container.width,
	container.height );
renderer.setClearColor("khaki", 0.25);	
// Ligar elemento <-> construtor
container.appendChild(renderer.domElement);

// Câmara para observar o modelo
const camera = new THREE.PerspectiveCamera(
	35,       // abertura
	container.width/container.height,  // proporção largura/altura
	0.1,      // corte perto
	10000     // corte longe
	);
camera.position.set( -2.5, 0, 20 );

// Controlos da câmara
const controls = new OrbitControls( 
	camera, 
	renderer.domElement );

// Cena do modelo (raiz)
const scene = new THREE.Scene();
// Orientar a câmara para a cena
camera.lookAt(scene.position);

// Uma geometria (caixa)
const geometry = new THREE.BoxGeometry( 5, 5, 5 );
// Um material (cor)
const material = new THREE.MeshLambertMaterial( {color: "steelblue"} );
// Um objecto gráfico (geometria + material)
const mesh = new THREE.Mesh( geometry, material );
// Ligar cena <-> objecto gráfica
scene.add( mesh );

// Uma luz
const light = new THREE.AmbientLight( "white" );
// Ligar cena <-> luz
scene.add( light );

// Processo da animação
function animate() {
	controls.update();              // Atualizar os controlos
	mesh.rotation.y += 0.01;        // Atualizar o modelo
	renderer.render(scene, camera); // Construir a cena atualizada
}

renderer.setAnimationLoop( animate );	// Ligar animação <-> construtor
		</script>
	</body>
</html>

Código e Documento separados

Parte HTML (Documento)

Atenção ao seguinte:

  • A linha "prog": "./prog.js" no importmap define o nome "prog" para importar o código que está no ficheiro ./prog.js.

  • No segundo elemento script:

    • O tipo module, necessário para se utilizar sistema de módulos da Javascript;
    • A instrução import main from "prog": na primeira linha desse elemento: Esta instrução importa para este elemento o código referido pelo nome "prog" definido no importmap acima.

Ficheiro doc.html:

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>Modelo + Documento 3JS</title>
		<meta charset="utf-8">
		<script type="importmap">
			{
				"imports": {
					"three": "./lib/threejs/build/three.module.js",
					"three/addons/": "./lib/threejs/addons/jsm/",

					"prog": "./prog.js"
				}
			}
		</script>
	</head>

	<body>
		<div id="3js:container">
		</div>

		<script type="module">
			import main from "prog";
			main();
		</script>

	</body>
</html>

Parte Javascript (Programa)

Atenção: A declaração export default fucntion main() (em prog.js) é necessária para permitir-se o acesso «externo» a esta função.

Ficheiro prog.js

// Bibliotecas			
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

export default function main() {
	// Elemento HTML com o modelo gráfico
	const container = document.getElementById("3js:container");
	container.width = 512;
	container.height = 512;

	// Construtor (Renderer) do modelo gráfico
	const renderer = new THREE.WebGLRenderer({ alpha: true });
	renderer.setPixelRatio(window.devicePixelRatio);
	renderer.setSize(
		container.width,
		container.height);
	renderer.setClearColor("khaki", 0.25);
	// Ligar elemento <-> construtor
	container.appendChild(renderer.domElement);

	// Câmara para observar o modelo
	const camera = new THREE.PerspectiveCamera(
		35,       // abertura
		container.width / container.height,  // proporção largura/altura
		0.1,      // corte perto
		10000     // corte longe
	);
	camera.position.set(-2.5, 0, 20);

	// Controlos da câmara
	const controls = new OrbitControls(
		camera,
		renderer.domElement);

	// Cena do modelo (raiz)
	const scene = new THREE.Scene();
	// Orientar a câmara para a cena
	camera.lookAt(scene.position);

	// Uma geometria (caixa)
	const geometry = new THREE.BoxGeometry(5, 5, 5);
	// Um material (cor)
	const material = new THREE.MeshLambertMaterial({ color: "steelblue" });
	// Um objecto gráfico (geometria + material)
	const mesh = new THREE.Mesh(geometry, material);
	// Ligar cena <-> objecto gráfica
	scene.add(mesh);

	// Uma luz
	const light = new THREE.AmbientLight("white");
	// Ligar cena <-> luz
	scene.add(light);

	// Processo da animação
	function animate() {
		controls.update();					// Atualizar os controlos
		mesh.rotation.y += 0.01;			// Atualizar o modelo
		renderer.render(scene, camera);		// Construir a cena atualizada
	}

	renderer.setAnimationLoop(animate);	// Ligar animação <-> construtor
}

Geometria por Faces com mapa UV

Veja como obter mapas de reflexos e de normais em NormalMap-Online.

Geometria e mapa UV

O three.js suporta geometrias definidas por faces, e aplicação de texturas por mapas uv. A função seguinte define uma geometria por faces com um papa UV

function IndexedFaceGeometry(vertices, faces, points, sectors) {
    //
    //  Geometry: "Indexed Face Set"
    //
    //  Generate all the vertexes in the XYZ plane
    const positions = [];
    for (const i of faces) {
        const xyz_point = vertices.slice(3 * i, 3 * i + 3);
        positions.push(...xyz_point);
    }
    //
    //  Generate all the points in the UV plane 
    const uvs = [];
    for (const i of sectors) {
        const uv_point = points.slice(2 * i, 2 * i + 2);
        uvs.push(...uv_point);
    }
    //
    const geo = new THREE.BufferGeometry();
    //
    geo.setAttribute("position",
        new THREE.Float32BufferAttribute(positions, 3));
    geo.setAttribute("uv",
        new THREE.Float32BufferAttribute(uvs, 2));
    //
    geo.computeVertexNormals();
    geo.computeBoundingSphere();
    //
    return geo;
}

Textura com mapas de difusão, reflexos e normais

const textureLoader = new THREE.TextureLoader();

const diffuseMap = textureLoader.load('[ mapa de DIFUSÃO ]');
const specularMap = textureLoader.load('[ mapa de REFLEXOS ]');
const normalMap = textureLoader.load('[ mapa de NORMAIS ]');

const material = new THREE.MeshPhongMaterial( {
	map: diffuseMap,
	specularMap: specularMap,
	normalMap: normalMap
} );